"""
Page Asist - Aplicație FastAPI pentru conversații multi-AI cu Ollama
"""
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, HTTPException, Query
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi.responses import FileResponse, JSONResponse
from fastapi.requests import Request
from pathlib import Path
import asyncio
import json
from typing import Optional

from backend.models import (
    ConversationConfig,
    ModelListResponse,
    ConversationHistoryItem,
    StreamMessage
)
from backend.mock_ollama import enhanced_get_available_models, enhanced_test_ollama_connection
from backend.conversation_manager import (
    create_conversation,
    get_conversation,
    remove_conversation
)
from backend.utils import load_conversation_metadata
from backend.database import ConversationDB

# Inițializare aplicație
app = FastAPI(
    title="Page Asist",
    description="Aplicație web pentru gestionarea conversațiilor multi-AI cu Ollama",
    version="1.0.0"
)

# Directoare
BASE_DIR = Path(__file__).parent
STATIC_DIR = BASE_DIR / "static"
TEMPLATES_DIR = BASE_DIR / "templates"
CONVERSATIONS_DIR = BASE_DIR / "conversations"

# Mount static files și templates
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
templates = Jinja2Templates(directory=str(TEMPLATES_DIR))


# === ENDPOINTS HTTP ===

@app.get("/")
async def home(request: Request):
    """Pagina principală"""
    return templates.TemplateResponse("index.html", {"request": request})


@app.get("/api/health")
async def health_check():
    """Health check endpoint"""
    return {"status": "ok", "service": "Page Asist"}


@app.get("/api/models", response_model=ModelListResponse)
async def get_models(
    ip: str = Query(..., description="Adresa IP a serverului Ollama"),
    port: str = Query("11434", description="Port server Ollama")
):
    """
    Obține lista de modele disponibile de la un server Ollama
    """
    try:
        models = await enhanced_get_available_models(ip, port, timeout=10)
        return ModelListResponse(
            success=True,
            models=models
        )
    except Exception as e:
        return ModelListResponse(
            success=False,
            models=[],
            error=str(e)
        )


@app.post("/api/test-connection")
async def test_connection(ip: str, port: str = "11434"):
    """
    Testează conexiunea cu un server Ollama
    """
    result = await enhanced_test_ollama_connection(ip, port)
    return result


@app.get("/api/history")
async def get_history():
    """
    Obține lista de conversații salvate
    """
    try:
        conversations = load_conversation_metadata()
        return {
            "success": True,
            "conversations": conversations
        }
    except Exception as e:
        return {
            "success": False,
            "error": str(e),
            "conversations": []
        }


@app.get("/api/history/{conversation_id}/download")
async def download_conversation(
    conversation_id: str,
    format: str = Query("txt", pattern="^(txt|docx)$")
):
    """
    Descarcă o conversație salvată în format TXT sau DOCX
    """
    file_path = CONVERSATIONS_DIR / f"{conversation_id}.{format}"
    
    if not file_path.exists():
        raise HTTPException(status_code=404, detail="Conversație negăsită")
    
    media_type = "text/plain" if format == "txt" else "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
    
    return FileResponse(
        path=str(file_path),
        media_type=media_type,
        filename=f"{conversation_id}.{format}"
    )


@app.get("/api/history/{conversation_id}/preview")
async def preview_conversation(conversation_id: str):
    """
    Obține preview-ul unei conversații salvate din baza de date
    """
    try:
        # Încearcă să încărce din baza de date
        conversation = ConversationDB.get_conversation_with_messages(conversation_id)
        
        if not conversation:
            # Fallback la fișierul JSON
            json_path = CONVERSATIONS_DIR / f"{conversation_id}.json"
            if not json_path.exists():
                raise HTTPException(status_code=404, detail="Conversație negăsită")
            
            with open(json_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            return {
                "success": True,
                "data": data
            }
        
        # Pregătește datele pentru preview din baza de date
        agenti_data = []
        for agent in conversation.agents:
            agenti_data.append({
                "url": f"{agent.ip}:{agent.port}",
                "rol": agent.rol,
                "model": agent.model,
                "max_tokens": agent.max_tokens
            })
        
        # Grupează mesajele pe runde
        messages_with_rounds = []
        current_round = 1
        messages_per_round = len(agenti_data)
        
        # Adaugă marcajele de rundă
        for i in range(0, len(conversation.messages), messages_per_round):
            messages_with_rounds.append({
                "type": "round_start",
                "round": current_round
            })
            
            for j in range(messages_per_round):
                if i + j < len(conversation.messages):
                    msg = conversation.messages[i + j]
                    messages_with_rounds.append({
                        "type": "message",
                        "timestamp": msg.timestamp.strftime("%Y-%m-%d %H:%M:%S"),
                        "agent_url": msg.agent_url,
                        "agent_role": msg.agent_role,
                        "content": msg.content,
                        "tokens": msg.tokens,
                        "idei_noi": msg.idei_noi
                    })
            
            current_round += 1
        
        data = {
            "id": conversation.id,
            "subiect": conversation.subiect,
            "start_time": conversation.start_time.isoformat() if conversation.start_time else None,
            "end_time": conversation.end_time.isoformat() if conversation.end_time else None,
            "numar_runde": conversation.numar_runde,
            "agenti": agenti_data,
            "mesaje": messages_with_rounds,
            "total_mesaje": conversation.total_mesaje,
            "total_idei_unice": conversation.total_idei_unice
        }
        
        return {
            "success": True,
            "data": data
        }
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Eroare la citire: {str(e)}")


@app.delete("/api/history/{conversation_id}")
async def delete_conversation(conversation_id: str):
    """
    Șterge o conversație salvată din baza de date și fișiere
    """
    deleted_files = []
    errors = []
    
    try:
        # Încearcă să ștergi din baza de date
        db_deleted = ConversationDB.delete_conversation(conversation_id)
        
        if not db_deleted:
            # Nu s-a găsit în baza de date, verifică fișierele
            found_files = False
            for ext in ["json", "txt", "docx"]:
                file_path = CONVERSATIONS_DIR / f"{conversation_id}.{ext}"
                if file_path.exists():
                    found_files = True
                    try:
                        file_path.unlink()
                        deleted_files.append(f"{conversation_id}.{ext}")
                    except Exception as e:
                        errors.append(f"Eroare la ștergere {ext}: {str(e)}")
            
            if not found_files:
                raise HTTPException(status_code=404, detail="Conversație negăsită")
        else:
            # Șterge și fișierele asociate dacă există
            for ext in ["json", "txt", "docx"]:
                file_path = CONVERSATIONS_DIR / f"{conversation_id}.{ext}"
                if file_path.exists():
                    try:
                        file_path.unlink()
                        deleted_files.append(f"{conversation_id}.{ext}")
                    except Exception as e:
                        errors.append(f"Eroare la ștergere {ext}: {str(e)}")
        
        return {
            "success": len(errors) == 0,
            "deleted_files": deleted_files,
            "errors": errors,
            "deleted_from_db": db_deleted
        }
        
    except HTTPException:
        raise
    except Exception as e:
        return {
            "success": False,
            "deleted_files": deleted_files,
            "errors": [f"Eroare generală: {str(e)}"]
        }


# === WEBSOCKET ENDPOINT ===

class ConnectionManager:
    """Manager pentru conexiuni WebSocket"""
    
    def __init__(self):
        self.active_connections: dict[str, WebSocket] = {}
    
    async def connect(self, websocket: WebSocket, client_id: str):
        await websocket.accept()
        self.active_connections[client_id] = websocket
    
    def disconnect(self, client_id: str):
        if client_id in self.active_connections:
            del self.active_connections[client_id]
    
    async def send_message(self, message: dict, client_id: str):
        if client_id in self.active_connections:
            await self.active_connections[client_id].send_json(message)


manager = ConnectionManager()


@app.websocket("/ws/{client_id}")
async def websocket_endpoint(websocket: WebSocket, client_id: str):
    """
    WebSocket endpoint pentru streaming live al conversațiilor
    """
    await manager.connect(websocket, client_id)
    conversation_manager = None
    
    try:
        while True:
            # Așteaptă mesaje de la client
            data = await websocket.receive_json()
            action = data.get("action")
            
            if action == "start":
                # Pornește o conversație nouă
                try:
                    config_data = data.get("config")
                    config = ConversationConfig(**config_data)
                    
                    # Creează managerul de conversație
                    conversation_manager = create_conversation(config)
                    
                    # Callback pentru trimitere mesaje prin WebSocket
                    async def ws_callback(stream_msg: StreamMessage):
                        await manager.send_message(
                            {
                                "type": stream_msg.type,
                                "data": stream_msg.data
                            },
                            client_id
                        )
                    
                    # Trimite confirmare pornire
                    await manager.send_message(
                        {
                            "type": "started",
                            "data": {
                                "conversation_id": conversation_manager.state.id,
                                "message": "Conversație pornită cu succes"
                            }
                        },
                        client_id
                    )
                    
                    # Pornește conversația (asincron)
                    await conversation_manager.start(ws_callback)
                    
                    # Salvează conversația
                    saved_files = conversation_manager.save()
                    
                    # Trimite confirmare salvare
                    await manager.send_message(
                        {
                            "type": "saved",
                            "data": {
                                "conversation_id": conversation_manager.state.id,
                                "files": saved_files,
                                "message": "Conversație salvată cu succes"
                            }
                        },
                        client_id
                    )
                    
                    # Curăță managerul
                    remove_conversation(conversation_manager.state.id)
                    conversation_manager = None
                    
                except Exception as e:
                    await manager.send_message(
                        {
                            "type": "error",
                            "data": {
                                "message": f"Eroare la pornire conversație: {str(e)}"
                            }
                        },
                        client_id
                    )
            
            elif action == "stop":
                # Oprește conversația curentă
                if conversation_manager:
                    conversation_manager.stop()
                    
                    # Salvează conversația
                    try:
                        saved_files = conversation_manager.save()
                        
                        await manager.send_message(
                            {
                                "type": "stopped",
                                "data": {
                                    "conversation_id": conversation_manager.state.id,
                                    "files": saved_files,
                                    "message": "Conversație oprită și salvată"
                                }
                            },
                            client_id
                        )
                    except Exception as e:
                        await manager.send_message(
                            {
                                "type": "error",
                                "data": {
                                    "message": f"Eroare la salvare: {str(e)}"
                                }
                            },
                            client_id
                        )
                    
                    # Curăță managerul
                    remove_conversation(conversation_manager.state.id)
                    conversation_manager = None
                else:
                    await manager.send_message(
                        {
                            "type": "error",
                            "data": {
                                "message": "Nu există conversație activă"
                            }
                        },
                        client_id
                    )
            
            elif action == "ping":
                # Ping pentru keep-alive
                await manager.send_message(
                    {"type": "pong", "data": {}},
                    client_id
                )
    
    except WebSocketDisconnect:
        # Curăță la deconectare
        manager.disconnect(client_id)
        if conversation_manager:
            conversation_manager.stop()
            remove_conversation(conversation_manager.state.id)
    
    except Exception as e:
        print(f"Eroare WebSocket: {e}")
        manager.disconnect(client_id)
        if conversation_manager:
            conversation_manager.stop()
            remove_conversation(conversation_manager.state.id)


if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8002,
        reload=True
    )
