import os
from fastapi import FastAPI, UploadFile, File, Form, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse, Response
from fastapi.staticfiles import StaticFiles
from typing import Optional
import uvicorn
import base64
from pathlib import Path

# Import your existing modules
from core import AppConfig, StudentNationality
from repositories import StorageRepository, MinIOStorageRepository
from handlers import AudioMessageHandler, TextMessageHandler
from services import (
    AudioService, ChatService, HealthService, ResponseService, 
    ResponseManager, OpenAIService, AgentService, ConnectionPool, PGVectorService, ChatDatabaseService, LanguageSegmentationService
)

class DIContainer:
    def __init__(self):
        self.config = AppConfig.from_env()
        self.storage_repo = MinIOStorageRepository(self.config)
        self.response_manager = ResponseManager()
        
        # Initialize OpenAI and Agent services
        self.openai_service = OpenAIService()

        self.pool_handler = ConnectionPool(
            dbname=os.getenv("POSTGRES_DB"),
            user=os.getenv("POSTGRES_USER"),
            password=os.getenv("POSTGRES_PASSWORD"),
            host=os.getenv("DB_HOST"), # This is the crucial part
            port=int(os.getenv("DB_PORT"))
        )
        print(os.getenv("DB_HOST"), os.getenv("POSTGRES_DB"), os.getenv("POSTGRES_USER"))
        self.agent_service = AgentService(pool_handler=self.pool_handler)

        # Initialize services
        self.audio_service = AudioService(self.storage_repo, self.config.minio_bucket)
        self.segmentation_service = LanguageSegmentationService()
        self.chat_service = ChatService(
            self.storage_repo, 
            self.response_manager, 
            self.config,
            self.openai_service,
            self.agent_service,
            self.segmentation_service
        )
        self.response_service = ResponseService(self.response_manager, self.audio_service)
        self.health_service = HealthService(self.storage_repo, self.config)

def create_app() -> FastAPI:
    app = FastAPI(title="Unified Chat API with Local Agent")
    
    # Fixed CORS configuration for CapRover
    app.add_middleware(
        CORSMiddleware,
        allow_origins=[
            "https://voice-agent.caprover.al-arcade.com",
            "http://voice-agent.caprover.al-arcade.com",
            "http://localhost:8000",  # For local development
            "http://127.0.0.1:8000",
            "*"  # Allow all origins for testing - remove in production
        ],
        allow_credentials=True,
        allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
        allow_headers=[
            "Accept",
            "Accept-Language", 
            "Content-Language",
            "Content-Type",
            "Authorization",
            "X-Response-Text"
        ],
        expose_headers=["X-Response-Text"],
    )

    # Initialize dependencies
    container = DIContainer()
    
    # Print configuration
    print("MinIO Endpoint:", container.config.minio_endpoint)
    print("MinIO Bucket:", container.config.minio_bucket)
    print("OpenAI Service Available:", container.openai_service.is_available())
    print("Agent Service Available:", container.agent_service.is_available())

    # Serve static files if the directory exists
    static_path = Path("static")
    if static_path.exists():
        app.mount("/static", StaticFiles(directory=static_path), name="static")

    @app.get("/chat-interface")
    async def serve_audio_recorder():
        """Serve the audio recorder HTML file"""
        try:
            # Try to serve from static directory first
            static_file = Path("static/audio-recorder.html")
            if static_file.exists():
                return FileResponse(static_file)
            
            # Fallback to current directory
            current_file = Path("audio-recorder.html")
            if current_file.exists():
                return FileResponse(current_file)
            
            # If no file found, return an error
            raise HTTPException(status_code=404, detail="Audio recorder interface not found")
        except Exception as e:
            print(f"Error serving audio recorder: {e}")
            raise HTTPException(status_code=500, detail=f"Error serving interface: {str(e)}")

    @app.post("/chat")
    async def chat_handler(
        file: Optional[UploadFile] = File(None), 
        text: Optional[str] = Form(None),
        student_id: str = Form("student_001")
    ):
        """
        Handles incoming chat messages (either text or audio).
        Generates responses locally using the agent service.
        """
        try:
            if not student_id.strip():
                raise HTTPException(status_code=400, detail="Student ID is required")
            
            print(f"Processing message for student: {student_id}")
            print(f"Text: {text}")
            print(f"File: {file.filename if file else 'None'}")
            
            result = container.chat_service.process_message(
                student_id=student_id, 
                file=file, 
                text=text
            )
            
            print(f"Chat service result: {result}")
            return result
            
        except Exception as e:
            print(f"Error in chat handler: {str(e)}")
            raise HTTPException(status_code=500, detail=f"Chat processing error: {str(e)}")

    @app.get("/get-audio-response")
    async def get_audio_response():
        """Fetches the agent's text and audio response with proper CORS headers."""
        try:
            print("Getting audio response...")
            result = container.response_service.get_agent_response()
            
            if hasattr(result, 'status_code'):
                # This is already a Response object from response_service
                print(f"Response headers: {dict(result.headers)}")
                return result
            else:
                # If it's not a Response object, create one
                print("Creating new response object")
                response_text = result.get('text', 'No response available')
                
                # Encode the response text in base64 for the header
                encoded_text = base64.b64encode(response_text.encode('utf-8')).decode('utf-8')
                
                # Create response with proper headers
                response = Response(
                    content=result.get('audio', b''),
                    media_type="audio/mpeg",
                    headers={
                        "X-Response-Text": encoded_text,
                        "Access-Control-Expose-Headers": "X-Response-Text",
                        "Access-Control-Allow-Origin": "*",
                        "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
                        "Access-Control-Allow-Headers": "*"
                    }
                )
                
                print(f"Created response with headers: {dict(response.headers)}")
                return response
                
        except Exception as e:
            print(f"Error getting audio response: {str(e)}")
            raise HTTPException(status_code=500, detail=f"Audio response error: {str(e)}")

    @app.options("/chat")
    async def chat_options():
        """Handle preflight CORS requests for chat endpoint"""
        return Response(
            headers={
                "Access-Control-Allow-Origin": "*",
                "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
                "Access-Control-Allow-Headers": "*",
                "Access-Control-Max-Age": "86400"
            }
        )

    @app.options("/get-audio-response")
    async def audio_response_options():
        """Handle preflight CORS requests for audio response endpoint"""
        return Response(
            headers={
                "Access-Control-Allow-Origin": "*",
                "Access-Control-Allow-Methods": "GET, POST, OPTIONS", 
                "Access-Control-Allow-Headers": "*",
                "Access-Control-Expose-Headers": "X-Response-Text",
                "Access-Control-Max-Age": "86400"
            }
        )

    @app.get("/health")
    async def health_check():
        """Health check endpoint with agent service status"""
        try:
            health_status = container.health_service.get_health_status()
            # Add agent service status
            health_status.update({
                "openai_service_status": "available" if container.openai_service.is_available() else "unavailable",
                "agent_service_status": "available" if container.agent_service.is_available() else "unavailable",
                "minio_endpoint": container.config.minio_endpoint,
                "minio_bucket": container.config.minio_bucket
            })
            return health_status
        except Exception as e:
            print(f"Health check error: {e}")
            return {"status": "error", "message": str(e)}

    # Agent management endpoints
    @app.get("/conversation/stats")
    async def get_conversation_stats(student_id: str = "student_001"):
        """Get conversation statistics"""
        try:
            return container.chat_service.get_agent_stats(student_id)
        except Exception as e:
            print(f"Stats error: {e}")
            raise HTTPException(status_code=500, detail=str(e))

    @app.post("/conversation/clear")
    async def clear_conversation(student_id: str = Form("student_001")):
        """Clear conversation history"""
        try:
            return container.chat_service.clear_conversation(student_id)
        except Exception as e:
            print(f"Clear conversation error: {e}")
            raise HTTPException(status_code=500, detail=str(e))

    @app.post("/agent/system-prompt")
    async def set_system_prompt(request: dict):
        """Update the agent's system prompt"""
        try:
            prompt = request.get("prompt", "")
            if not prompt:
                raise HTTPException(status_code=400, detail="System prompt cannot be empty")
            return container.chat_service.set_system_prompt(prompt)
        except Exception as e:
            print(f"Set system prompt error: {e}")
            raise HTTPException(status_code=500, detail=str(e))

    @app.get("/agent/system-prompt")
    async def get_system_prompt():
        """Get the current system prompt"""
        try:
            return {
                "system_prompt": container.agent_service.system_prompt,
                "status": "success"
            }
        except Exception as e:
            print(f"Get system prompt error: {e}")
            raise HTTPException(status_code=500, detail=str(e))

    @app.get("/conversation/export")
    async def export_conversation(student_id: str = "student_001"):
        """Export conversation history"""
        try:
            history = container.agent_service.export_conversation(student_id)
            return {
                "student_id": student_id,
                "messages": history,
                "total_messages": len(history)
            }
        except Exception as e:
            print(f"Export conversation error: {e}")
            raise HTTPException(status_code=500, detail=str(e))

    @app.post("/conversation/import")
    async def import_conversation(request: dict):
        """Import conversation history"""
        try:
            student_id = request.get("student_id", "student_001")
            messages = request.get("messages", [])
            
            if not messages:
                raise HTTPException(status_code=400, detail="Messages list cannot be empty")
            
            container.agent_service.import_conversation(messages, student_id)
            return {
                "status": "success",
                "message": f"Imported {len(messages)} messages to conversation {student_id}"
            }
        except Exception as e:
            print(f"Import conversation error: {e}")
            raise HTTPException(status_code=500, detail=str(e))

    @app.get("/debug/test-response")
    async def debug_test_response():
        """Debug endpoint to test response generation"""
        try:
            # Test basic response
            test_text = "This is a test response"
            encoded_text = base64.b64encode(test_text.encode('utf-8')).decode('utf-8')
            
            return Response(
                content=b"test audio data",
                media_type="audio/mpeg",
                headers={
                    "X-Response-Text": encoded_text,
                    "Access-Control-Expose-Headers": "X-Response-Text"
                }
            )
        except Exception as e:
            print(f"Debug test error: {e}")
            raise HTTPException(status_code=500, detail=str(e))

    @app.get("/")
    async def root():
        """Root endpoint with API info"""
        return {
            "service": "Unified Chat API with Local Agent",
            "version": "2.1.0",
            "description": "Unified backend for audio/text chat with a local AI agent.",
            "status": "running",
            "deployment": "CapRover",
            "features": [
                "Local AI agent responses using OpenAI GPT",
                "Audio transcription using OpenAI Whisper", 
                "Text-to-speech using OpenAI TTS",
                "Conversation history management",
                "Student-specific conversations",
                "CORS enabled for cross-origin requests"
            ],
            "endpoints": {
                "chat_interface": "/chat-interface (HTML interface)",
                "chat": "/chat (accepts audio or text with student_id)",
                "get_audio_response": "/get-audio-response (fetches agent's audio and text)",
                "health": "/health (service health check)",
                "debug": "/debug/test-response (test response generation)"
            }
        }
    
    return app

# Application entry point
app = create_app()

if __name__ == "__main__":
    # For development
    uvicorn.run(
        "main:app", 
        host="0.0.0.0", 
        port=int(os.environ.get("PORT", 8000)),
        reload=True
    )