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

# Import your existing modules
from core import AppConfig
from repositories import MinIOStorageRepository
from services import (
    AudioService, ChatService, HealthService, ResponseService, 
    ResponseManager, OpenAIService, AgentService, ConnectionPool, 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"),
            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)


@asynccontextmanager
async def lifespan(app: FastAPI):
    """
    Manages application startup and shutdown events for resource safety.
    """
    # --- Code to run ON STARTUP ---
    print("Application starting up...")
    container = DIContainer()
    app.state.container = container 
    print("DIContainer created and database pool initialized.")
    
    yield # The application is now running and handling requests
    
    # --- Code to run ON SHUTDOWN ---
    print("Application shutting down...")
    # This is the guaranteed, graceful shutdown call
    app.state.container.agent_service.close() 
    print("Database connection pool closed successfully.")


def create_app() -> FastAPI:
    # Connect the lifespan manager to your FastAPI app instance
    app = FastAPI(title="Unified Chat API with Local Agent", lifespan=lifespan)
    
    # 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"],
    )


    # 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.on_event("startup")
    async def startup_event():
        # Access the container from app state to print config on startup
        container = app.state.container
        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())

    @app.get("/chat-interface")
    async def serve_audio_recorder():
        """Serve the audio recorder HTML file"""
        try:
            static_file = Path("static/audio-recorder.html")
            if static_file.exists():
                return FileResponse(static_file)
            current_file = Path("audio-recorder.html")
            if current_file.exists():
                return FileResponse(current_file)
            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(
        request: Request,
        file: Optional[UploadFile] = File(None), 
        text: Optional[str] = Form(None),
        student_id: str = Form("student_001"),
        game_context: Optional[str] = Form(None) 
    ):
        """Handles incoming chat messages using the shared container instance."""
        container = request.app.state.container
        try:
            if not student_id.strip():
                raise HTTPException(status_code=400, detail="Student ID is required")
            
            result = container.chat_service.process_message(
                student_id=student_id, 
                file=file, 
                text=text,
                game_context=game_context
            )
            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(request: Request, student_id: str = "student_001"):
        """Fetches the agent's text and audio response using the shared container."""
        container = request.app.state.container
        try:
            result = container.response_service.get_agent_response(student_id=student_id)
            if hasattr(result, 'status_code'):
                return result
            # This should be unreachable if response_service always returns a Response object
            return result
        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(status_code=204, headers={"Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "POST, OPTIONS", "Access-Control-Allow-Headers": "*"})

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

    @app.get("/health")
    async def health_check(request: Request):
        """Health check endpoint using the shared container."""
        container = request.app.state.container
        try:
            health_status = container.health_service.get_health_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(request: Request, student_id: str = "student_001"):
        container = request.app.state.container
        try:
            return container.chat_service.get_agent_stats(student_id)
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    @app.post("/conversation/clear")
    async def clear_conversation(request: Request, student_id: str = Form("student_001")):
        container = request.app.state.container
        try:
            return container.chat_service.clear_conversation(student_id)
        except Exception as e:
            raise HTTPException(status_code=500, detail=str(e))

    @app.post("/agent/system-prompt")
    async def set_system_prompt(req_body: dict, request: Request):
        container = request.app.state.container
        try:
            prompt = req_body.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:
            raise HTTPException(status_code=500, detail=str(e))

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

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

    @app.post("/conversation/import")
    async def import_conversation(req_body: dict, request: Request):
        container = request.app.state.container
        try:
            student_id = req_body.get("student_id", "student_001")
            messages = req_body.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"}
        except Exception as 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"""
        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"})

    @app.get("/")
    async def root():
        """Root endpoint with API info"""
        return {"service": "Unified Chat API with Local Agent", "version": "2.2.0-lifespan", "status": "running"}
    
    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
    )