"""
FastAPI backend for Smart Farm Photo Keyword Tagging AI
"""

import os
import sys
import io
import base64
from typing import List, Dict, Optional
from datetime import datetime
import asyncio
import json

from fastapi import FastAPI, File, UploadFile, HTTPException, BackgroundTasks
from fastapi.responses import HTMLResponse, JSONResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from PIL import Image

# Add src to path for imports
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))

from data.image_processor import ImageProcessor
from model.keyword_generator import AgricultureKeywordGenerator
from utils.validation import KeywordValidator, DataQualityChecker

# Initialize FastAPI app
app = FastAPI(
    title="Smart Farm Photo Keyword Tagging AI",
    description="AI-powered agricultural photo keyword generation system",
    version="1.0.0",
    docs_url="/docs",
    redoc_url="/redoc"
)

# Add CORS middleware
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Mount static files for serving images
app.mount("/static", StaticFiles(directory="../../data"), name="static")

# Create uploads directory for temporary image storage
uploads_dir = "uploads"
os.makedirs(uploads_dir, exist_ok=True)
app.mount("/uploads", StaticFiles(directory=uploads_dir), name="uploads")

def cleanup_old_uploads():
    """Clean up uploaded files older than 1 hour"""
    try:
        import time
        current_time = time.time()
        for filename in os.listdir(uploads_dir):
            file_path = os.path.join(uploads_dir, filename)
            if os.path.isfile(file_path):
                # Remove files older than 1 hour (3600 seconds)
                if current_time - os.path.getctime(file_path) > 3600:
                    os.remove(file_path)
                    print(f"Cleaned up old upload: {filename}")
    except Exception as e:
        print(f"Error during cleanup: {e}")

# Global components (initialized on startup)
image_processor = None
keyword_generator = None
validator = None

# Pydantic models for API
class KeywordResponse(BaseModel):
    filename: str
    keywords: List[str]
    title: str
    quality_score: float
    processing_time: float
    caption: str
    image_url: Optional[str] = None

class BatchResponse(BaseModel):
    total_images: int
    successful: int
    failed: int
    results: List[KeywordResponse]
    average_quality: float
    total_processing_time: float

class SystemStatus(BaseModel):
    status: str
    model_loaded: bool
    version: str
    capabilities: List[str]

@app.on_event("startup")
async def startup_event():
    """Initialize AI components on startup"""
    global image_processor, keyword_generator, validator
    
    print("🚜 Initializing Smart Farm AI System...")
    
    try:
        image_processor = ImageProcessor()
        keyword_generator = AgricultureKeywordGenerator()
        validator = KeywordValidator()
        print("✅ AI System initialized successfully!")
    except Exception as e:
        print(f"❌ Failed to initialize AI system: {e}")
        raise

@app.get("/", response_class=HTMLResponse)
async def root():
    """Serve the main UI page"""
    html_content = """
    <!DOCTYPE html>
    <html>
    <head>
        <title>Smart Farm Photo Keyword Tagging AI</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <style>
            body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background: #f5f5f5; }
            .container { max-width: 1200px; margin: 0 auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
            .header { text-align: center; margin-bottom: 30px; }
            .header h1 { color: #2c5530; margin: 0; }
            .header p { color: #666; margin: 10px 0; }
            .upload-area { border: 2px dashed #4CAF50; border-radius: 10px; padding: 40px; text-align: center; margin: 20px 0; background: #f9f9f9; }
            .upload-area:hover { background: #f0f8f0; }
            .btn { background: #4CAF50; color: white; padding: 12px 24px; border: none; border-radius: 5px; cursor: pointer; font-size: 16px; }
            .btn:hover { background: #45a049; }
            .btn:disabled { background: #ccc; cursor: not-allowed; }
            .results { margin-top: 30px; }
            .result-card { background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 8px; padding: 20px; margin: 10px 0; display: flex; gap: 20px; }
            .image-preview { flex-shrink: 0; }
            .image-preview img { max-width: 200px; max-height: 150px; border-radius: 8px; object-fit: cover; border: 2px solid #ddd; }
            .result-content { flex-grow: 1; }
            .keywords { display: flex; flex-wrap: wrap; gap: 8px; margin: 10px 0; }
            .keyword { background: #e7f3ff; color: #0066cc; padding: 4px 8px; border-radius: 4px; font-size: 14px; }
            .quality-score { font-weight: bold; }
            .quality-high { color: #28a745; }
            .quality-medium { color: #ffc107; }
            .quality-low { color: #dc3545; }
            .loading { display: none; text-align: center; margin: 20px 0; }
            .status { padding: 10px; border-radius: 5px; margin: 10px 0; }
            .status.success { background: #d4edda; color: #155724; border: 1px solid #c3e6cb; }
            .status.warning { background: #fff3cd; color: #856404; border: 1px solid #ffeaa7; }
            .status.error { background: #f8d7da; color: #721c24; border: 1px solid #f5c6cb; }
            .demo-section { margin: 30px 0; padding: 20px; background: #e8f5e8; border-radius: 8px; }
            .api-docs { margin: 20px 0; }
            .api-docs a { color: #4CAF50; text-decoration: none; font-weight: bold; }
            .api-docs a:hover { text-decoration: underline; }
        </style>
    </head>
    <body>
        <div class="container">
            <div class="header">
                <h1>🚜 Smart Farm Photo Keyword Tagging AI</h1>
                <p>AI-powered agricultural photo keyword generation system</p>
                <p><strong>Status:</strong> <span id="system-status">Loading...</span></p>
            </div>

            <div class="demo-section">
                <h3>🎯 System Demonstration</h3>
                <p>Upload agricultural photos to see AI-generated keywords, titles, and quality scores in real-time.</p>
                <button class="btn" onclick="runDemo()">🧪 Run Demo with Sample Images</button>
            </div>

            <div class="upload-area" onclick="document.getElementById('fileInput').click()">
                <h3>📸 Upload Agricultural Photos</h3>
                <p>Click here or drag and drop images to analyze</p>
                <input type="file" id="fileInput" multiple accept="image/*" style="display: none;" onchange="processFiles()">
            </div>

            <div class="loading" id="loading">
                <h3>🔄 Processing images...</h3>
                <p>AI is analyzing your agricultural photos</p>
            </div>

            <div class="results" id="results"></div>

            <div class="api-docs">
                <h3>📚 API Documentation</h3>
                <p><a href="/docs" target="_blank">📖 Interactive API Docs (Swagger)</a></p>
                <p><a href="/redoc" target="_blank">📋 Alternative API Docs (ReDoc)</a></p>
                <p><a href="/status" target="_blank">🔍 System Status API</a></p>
            </div>
        </div>

        <script>
            // Check system status on load
            fetch('/status')
                .then(response => response.json())
                .then(data => {
                    document.getElementById('system-status').innerHTML = 
                        `<span style="color: ${data.model_loaded ? 'green' : 'red'}">${data.status}</span>`;
                })
                .catch(error => {
                    document.getElementById('system-status').innerHTML = 
                        '<span style="color: red">Error loading status</span>';
                });

            async function processFiles() {
                const fileInput = document.getElementById('fileInput');
                const files = fileInput.files;
                
                if (files.length === 0) return;
                
                document.getElementById('loading').style.display = 'block';
                document.getElementById('results').innerHTML = '';
                
                const formData = new FormData();
                for (let file of files) {
                    formData.append('files', file);
                }
                
                try {
                    const response = await fetch('/analyze/batch', {
                        method: 'POST',
                        body: formData
                    });
                    
                    const result = await response.json();
                    displayResults(result);
                } catch (error) {
                    showError('Error processing images: ' + error.message);
                } finally {
                    document.getElementById('loading').style.display = 'none';
                }
            }

            async function runDemo() {
                document.getElementById('loading').style.display = 'block';
                document.getElementById('results').innerHTML = '';
                
                try {
                    const response = await fetch('/demo');
                    const result = await response.json();
                    displayResults(result);
                } catch (error) {
                    showError('Error running demo: ' + error.message);
                } finally {
                    document.getElementById('loading').style.display = 'none';
                }
            }

            function displayResults(data) {
                const resultsDiv = document.getElementById('results');
                
                let html = `
                    <h3>📊 Processing Results</h3>
                `;

                if (data.successful === 0 && data.failed > 0) {
                    html += `
                        <div class="status error">
                            ❌ Failed to process ${data.failed} image(s)<br>
                            💡 <strong>Tips:</strong><br>
                            • Make sure you're uploading valid image files (JPG, PNG, GIF, etc.)<br>
                            • Try converting your image to JPG format<br>
                            • Check that the file isn't corrupted<br>
                            • Supported formats: JPEG, PNG, GIF, BMP, TIFF
                        </div>
                    `;
                } else {
                    html += `
                        <div class="status ${data.failed > 0 ? 'warning' : 'success'}">
                            ✅ Processed ${data.successful}/${data.total_images} images successfully<br>
                            ${data.failed > 0 ? `⚠️ ${data.failed} image(s) failed to process<br>` : ''}
                            ⏱️ Total time: ${(data.total_processing_time || 0).toFixed(1)}s<br>
                            🎯 Average quality: ${(data.average_quality || 0).toFixed(1)}/100
                        </div>
                    `;
                }
                
                data.results.forEach((result, index) => {
                    const qualityScore = result.quality_score || 0;
                    const qualityClass = qualityScore >= 70 ? 'quality-high' :
                                       qualityScore >= 50 ? 'quality-medium' : 'quality-low';

                    // Create image URL for sample images or uploaded images
                    const imageUrl = result.image_url || `/static/working_images/${result.filename}`;

                    html += `
                        <div class="result-card">
                            <div class="image-preview">
                                <img src="${imageUrl}" alt="${result.filename}"
                                     onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';"
                                     onload="this.nextElementSibling.style.display='none';">
                                <div class="image-placeholder" style="display:none; width:200px; height:150px; background:#f0f0f0;
                                           border-radius:8px; align-items:center; justify-content:center;
                                           color:#666; font-size:14px;">📸 Image not available</div>
                            </div>
                            <div class="result-content">
                                <h4>📸 ${result.filename}</h4>
                                <p><strong>Title:</strong> ${result.title}</p>
                                <p><strong>Keywords:</strong></p>
                                <div class="keywords">
                                    ${result.keywords.map(k => `<span class="keyword">${k}</span>`).join('')}
                                </div>
                                <p><strong>Quality Score:</strong>
                                    <span class="quality-score ${qualityClass}">${qualityScore}/100</span>
                                </p>
                                <p><strong>Processing Time:</strong> ${(result.processing_time || 0).toFixed(1)}s</p>
                            </div>
                        </div>
                    `;
                });
                
                resultsDiv.innerHTML = html;
            }

            function showError(message) {
                document.getElementById('results').innerHTML = 
                    `<div class="status error">❌ ${message}</div>`;
            }
        </script>
    </body>
    </html>
    """
    return html_content

@app.get("/status", response_model=SystemStatus)
async def get_system_status():
    """Get system status and capabilities"""
    return SystemStatus(
        status="Operational" if keyword_generator else "Error",
        model_loaded=keyword_generator is not None,
        version="1.0.0",
        capabilities=[
            "Agricultural keyword generation",
            "Image title creation",
            "Quality validation",
            "Batch processing",
            "Agricultural distinctions (farmer vs rancher)",
            "Location extraction",
            "Performance metrics"
        ]
    )

@app.post("/analyze/single", response_model=KeywordResponse)
async def analyze_single_image(file: UploadFile = File(...)):
    """Analyze a single agricultural image"""
    if not keyword_generator:
        raise HTTPException(status_code=500, detail="AI system not initialized")
    
    try:
        # Read and validate image
        contents = await file.read()

        # Validate file is an image
        if not file.content_type or not file.content_type.startswith('image/'):
            raise ValueError(f"File {file.filename} is not a valid image")

        # Create BytesIO object and open image
        image_bytes = io.BytesIO(contents)
        image = Image.open(image_bytes)

        # Convert to RGB if necessary (handles RGBA, P mode, etc.)
        if image.mode not in ('RGB', 'L'):
            image = image.convert('RGB')

        # Save temporarily for processing and display
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S_%f')
        safe_filename = f"{timestamp}_{file.filename.replace(' ', '_')}"
        temp_path = f"temp_{safe_filename}"
        upload_path = f"uploads/{safe_filename}"

        # Save both temp file for processing and upload file for display
        image.save(temp_path, format='JPEG')
        image.save(upload_path, format='JPEG')

        start_time = datetime.now()

        # Generate keywords
        ai_results = keyword_generator.generate_keywords(temp_path)

        # Validate quality
        quality_result = validator.validate_keywords(ai_results['keywords'])

        processing_time = (datetime.now() - start_time).total_seconds()

        # Clean up temp file (keep upload file for display)
        os.remove(temp_path)
        
        return KeywordResponse(
            filename=file.filename,
            keywords=ai_results['keywords'],
            title=ai_results['title'],
            quality_score=quality_result['score'],
            processing_time=processing_time,
            caption=ai_results['caption'],
            image_url=f"/uploads/{safe_filename}"
        )
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Error processing image: {str(e)}")

@app.post("/analyze/batch", response_model=BatchResponse)
async def analyze_batch_images(files: List[UploadFile] = File(...)):
    """Analyze multiple agricultural images"""
    if not keyword_generator:
        raise HTTPException(status_code=500, detail="AI system not initialized")

    # Clean up old uploads periodically
    cleanup_old_uploads()

    results = []
    failed = 0
    start_time = datetime.now()
    
    for file in files:
        try:
            # Process each file
            contents = await file.read()

            # Validate file is an image
            if not file.content_type or not file.content_type.startswith('image/'):
                raise ValueError(f"File {file.filename} is not a valid image")

            # Create BytesIO object and open image
            image_bytes = io.BytesIO(contents)
            image = Image.open(image_bytes)

            # Convert to RGB if necessary (handles RGBA, P mode, etc.)
            if image.mode not in ('RGB', 'L'):
                image = image.convert('RGB')

            # Save temporarily for processing and display
            timestamp = datetime.now().strftime('%Y%m%d_%H%M%S_%f')
            safe_filename = f"{timestamp}_{file.filename.replace(' ', '_')}"
            temp_path = f"temp_{safe_filename}"
            upload_path = f"uploads/{safe_filename}"

            # Save both temp file for processing and upload file for display
            image.save(temp_path, format='JPEG')
            image.save(upload_path, format='JPEG')

            file_start = datetime.now()
            ai_results = keyword_generator.generate_keywords(temp_path)
            quality_result = validator.validate_keywords(ai_results['keywords'])
            file_time = (datetime.now() - file_start).total_seconds()

            results.append(KeywordResponse(
                filename=file.filename,
                keywords=ai_results['keywords'],
                title=ai_results['title'],
                quality_score=quality_result['score'],
                processing_time=file_time,
                caption=ai_results['caption'],
                image_url=f"/uploads/{safe_filename}"
            ))

            # Clean up temp file (keep upload file for display)
            os.remove(temp_path)
            
        except Exception as e:
            failed += 1
            error_msg = f"Error processing {file.filename}: {str(e)}"
            print(error_msg)
            # Add error details to help debugging
            if "cannot identify image file" in str(e):
                print(f"  - File type: {file.content_type}")
                print(f"  - File size: {len(contents) if 'contents' in locals() else 'unknown'} bytes")
            # You could also add failed files to results with error info if needed
    
    total_time = (datetime.now() - start_time).total_seconds()
    avg_quality = sum(r.quality_score for r in results) / len(results) if results else 0.0

    return BatchResponse(
        total_images=len(files),
        successful=len(results),
        failed=failed,
        results=results,
        average_quality=float(avg_quality),
        total_processing_time=float(total_time)
    )

@app.get("/demo", response_model=BatchResponse)
async def run_demo():
    """Run demo with existing sample images"""
    if not keyword_generator:
        raise HTTPException(status_code=500, detail="AI system not initialized")
    
    # Use existing sample images
    sample_dir = "../../data/working_images"
    if not os.path.exists(sample_dir):
        raise HTTPException(status_code=404, detail="Sample images not found")
    
    image_files = image_processor.get_image_files(sample_dir)
    if not image_files:
        raise HTTPException(status_code=404, detail="No sample images available")
    
    results = []
    start_time = datetime.now()
    
    for img_path in image_files:
        try:
            file_start = datetime.now()
            ai_results = keyword_generator.generate_keywords(img_path)
            quality_result = validator.validate_keywords(ai_results['keywords'])
            file_time = (datetime.now() - file_start).total_seconds()
            
            # Create image URL for serving
            relative_path = os.path.relpath(img_path, "../../data")
            image_url = f"/static/{relative_path}"

            results.append(KeywordResponse(
                filename=os.path.basename(img_path),
                keywords=ai_results['keywords'],
                title=ai_results['title'],
                quality_score=quality_result['score'],
                processing_time=file_time,
                caption=ai_results['caption'],
                image_url=image_url
            ))
            
        except Exception as e:
            print(f"Error processing {img_path}: {e}")
    
    total_time = (datetime.now() - start_time).total_seconds()
    avg_quality = sum(r.quality_score for r in results) / len(results) if results else 0.0

    return BatchResponse(
        total_images=len(image_files),
        successful=len(results),
        failed=len(image_files) - len(results),
        results=results,
        average_quality=float(avg_quality),
        total_processing_time=float(total_time)
    )

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)
