# 🚀 Modal Deployment Script (Optimized Configuration)
# Generated by modal-for-noobs - https://github.com/arthrod/modal-for-noobs
# Deployment Mode: optimized
# Features: GPU-enabled deployment with ML libraries and performance optimization
# Timeout: {{ timeout_seconds }}s

import modal
import sys
import os
from pathlib import Path
from datetime import datetime
from loguru import logger
from fastapi import FastAPI
import gradio as gr
from gradio.routes import mount_gradio_app

# Configuration constants
APP_NAME = "{{ app_name }}"
APP_TITLE = "{{ app_name }} - Modal Optimized Deployment"
APP_DESCRIPTION = "GPU-optimized deployment with ML libraries"
DEPLOYMENT_MODE = "optimized"
TIMEOUT_SECONDS = {{ timeout_seconds }}
MAX_CONTAINERS = {{ max_containers }}
MIN_CONTAINERS = {{ min_containers }}

# Configure logging
logger.add(sys.stderr, format="{time} {level} {message}", level="INFO")

# Create Modal App
app = modal.App(APP_NAME)

{% if provision_nfs %}
# Persistent storage configuration
MOUNT_PATH = "/workspace"
volume = modal.Volume.persisted(f"{APP_NAME}-volume")
{% endif %}

# Container Image Configuration (Optimized for ML)
{{ image_config }}

# Original Application Code
{{ original_code }}

# Modal Function Configuration with GPU
@app.function(
    image=image,
    gpu="{{ gpu_type if gpu_type else 'any' }}",
    {% if num_gpus > 0 %}
    gpu_count={{ num_gpus }},
    {% endif %}
    min_containers={{ min_containers }},
    max_containers={{ max_containers }},
    timeout={{ timeout_seconds }},
    memory={{ memory_mb }},
    cpu={{ cpu }},
    {% if provision_nfs %}
    volumes={MOUNT_PATH: volume},
    {% endif %}
)
@modal.concurrent(max_inputs={{ concurrent_inputs }})
@modal.asgi_app()
def deploy_gradio():
    """Deploy Gradio app with GPU optimization on Modal."""
    
    # Check GPU availability
    try:
        import torch
        gpu_available = torch.cuda.is_available()
        gpu_name = torch.cuda.get_device_name(0) if gpu_available else "None"
        gpu_memory = torch.cuda.get_device_properties(0).total_memory / 1e9 if gpu_available else 0
        logger.info(f"GPU Status - Available: {gpu_available}, Device: {gpu_name}, Memory: {gpu_memory:.2f}GB")
    except ImportError:
        gpu_available = False
        gpu_name = "None"
        logger.warning("PyTorch not available, GPU detection skipped")
    
    # Detect Gradio Interface
    demo = None
    interface_names = ['demo', 'app', 'interface', 'iface']
    
    for name in interface_names:
        if name in globals() and hasattr(globals()[name], 'launch'):
            demo = globals()[name]
            logger.info(f"Found Gradio interface: {name}")
            break
    
    if demo is None:
        for var_name, var_value in globals().items():
            if hasattr(var_value, 'queue') and hasattr(var_value, 'launch'):
                demo = var_value
                logger.info(f"Found Gradio interface through scanning: {var_name}")
                break
    
    if demo is None:
        logger.error("No Gradio interface found")
        raise ValueError("Could not find Gradio interface")
    
    # Configure demo queue for high throughput
    demo.queue(max_size=50)
    
    # FastAPI Setup with enhanced monitoring
    fastapi_app = FastAPI(
        title=APP_TITLE,
        description=APP_DESCRIPTION,
        version="1.0.0",
        docs_url="/docs",
        redoc_url="/redoc"
    )
    
    # Health check with GPU info
    @fastapi_app.get("/health")
    async def health_check():
        return {
            "status": "healthy",
            "app_name": APP_NAME,
            "deployment_mode": DEPLOYMENT_MODE,
            "timestamp": datetime.now().isoformat(),
            "gpu_available": gpu_available,
            "gpu_name": gpu_name,
            "gpu_memory_gb": gpu_memory if 'gpu_memory' in locals() else 0,
        }
    
    # Performance metrics endpoint
    @fastapi_app.get("/metrics")
    async def metrics():
        import psutil
        
        return {
            "cpu_percent": psutil.cpu_percent(interval=1),
            "memory_percent": psutil.virtual_memory().percent,
            "disk_usage": psutil.disk_usage('/').percent,
            "gpu_utilization": torch.cuda.utilization() if gpu_available and 'torch' in locals() else 0,
        }
    
    logger.info("Mounting optimized Gradio app to FastAPI")
    
    # Mount Gradio app
    return mount_gradio_app(fastapi_app, demo, path="/")

if __name__ == "__main__":
    app.run()