from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from dotenv import load_dotenv
from lightrag import QueryParam
from datetime import datetime
from pathlib import Path
import asyncio
import json
import yaml
import os

from src.rag_config import rag_manager
from src.sync.orchestrator import SyncOrchestrator
from src.metrics import metrics, setup_logging

logger = setup_logging()

app = FastAPI(title="LightRAG API")

class QueryRequest(BaseModel):
    query: str
    project_id: str
    mode: str = "hybrid"
    top_k: int = 20

class QueryResponse(BaseModel):
    status: str
    context: str

class DeleteDocumentRequest(BaseModel):
    project_id: str
    doc_id: str

class UniversalResponse(BaseModel):
    status: str
    message: str

def load_config():
    with open('config.yaml', 'r', encoding='utf-8') as f:
        return yaml.safe_load(f)

def load_env() -> None:
    """Загрузка переменных окружения из .env файла."""
    load_dotenv()

sync_orchestrator = None

@app.on_event("startup")
async def startup_event():
    global sync_orchestrator

    sync_orchestrator = SyncOrchestrator(
        external_api_base=os.getenv('EXTERNAL_API_BASE'))
    
    load_env()
    logger.info("RAG система инициализирована для API")

    await sync_orchestrator.start_rebuild_scheduler()
    

@app.on_event("shutdown")
async def shutdown_event():
    global sync_orchestrator

    if sync_orchestrator:
        sync_orchestrator.stop()
        sync_orchestrator.stop_rebuild_scheduler()
    logger.info("Синхронизация проектов и планировщик перестройки остановлены")

@app.get("/metrics")
async def prometheus_metrics():
    """Эндпоинт для метрик Prometheus"""
    return await metrics()

@app.post("/query_context", response_model=QueryResponse)
async def query_context(input_data: QueryRequest) -> QueryResponse:
    """Получить только контекст из RAG системы по запросу"""
    try:
        project_rag = await rag_manager.get_rag_for_project(input_data.project_id, create_if_not_exists=False)
        
        if project_rag is None:
            return QueryResponse(status="успех", context='')
        
        result = await project_rag.query(
            input_data.query,
            param=QueryParam(
                mode=input_data.mode,
                top_k=input_data.top_k,
                only_need_context=True
            )
        )
        return QueryResponse(status="успех", context=result if result else '')
    
    except Exception as e:
        logger.error(f"Ошибка при выполнении запроса: {e}")
        raise HTTPException(status_code=500, detail=str(e))


@app.post("/delete", response_model=UniversalResponse)
async def delete_document(input_data: DeleteDocumentRequest) -> UniversalResponse:
    """Удалить документ из RAG системы по ID"""
    try:
        project_rag = await rag_manager.get_rag_for_project(input_data.project_id, create_if_not_exists=False)
        
        if project_rag is None:
            return UniversalResponse(status="успех", 
                                     message=f"Проект {input_data.project_id} не существует")
        
        await project_rag.delete_by_doc_id(input_data.doc_id)
        
        return UniversalResponse(status="успех", 
                                 message=f"Документ {input_data.doc_id} успешно удален из проекта {input_data.project_id}")
    
    except Exception as e:
        logger.error(f"Ошибка при удалении документа: {e}")
        raise HTTPException(status_code=500, detail=str(e))


# === ENDPOINTS ДЛЯ УПРАВЛЕНИЯ СИНХРОНИЗАЦИЕЙ ===

@app.post("/sync/force")
async def force_sync():
    """Принудительно запустить синхронизацию прямо сейчас"""
    try:
        if sync_orchestrator.force_sync_running:
            return {
                "status": "в_процессе",
                "message": "Принудительная синхронизация уже выполняется",
                "start_time": sync_orchestrator.force_sync_start_time.isoformat() if sync_orchestrator.force_sync_start_time else None
            }
        
        task = asyncio.create_task(sync_orchestrator.force_sync_projects())
        
        def log_completion(task):
            try:
                result = task.result()
                logger.info(f"Фоновая синхронизация завершена: {result}")
            except Exception as e:
                logger.error(f"Фоновая синхронизация завершилась с ошибкой: {e}")
        
        task.add_done_callback(log_completion)
        
        return {
            "status": "запущено", 
            "message": "Принудительная синхронизация запущена в фоновом режиме",
            "timestamp": datetime.utcnow().isoformat()
        }
    except Exception as e:
        logger.error(f"Ошибка запуска принудительной синхронизации: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/sync/status")
async def get_sync_status():
    """
    Получить статус синхронизации и информацию о планах перестройки
    
    ОБНОВЛЕНО: теперь показывает per-project sync информацию
    """
    try:
        state_file = "data/sync_state.json"
        last_sync = "Никогда"
        rebuild_info = {}
        project_syncs_info = {}
        
        if Path(state_file).exists():
            with open(state_file, 'r') as f:
                state = json.load(f)
                last_sync = state.get("last_sync_human", "Никогда")
                
                # Информация о синхронизации отдельных проектов (НОВОЕ!)
                project_syncs = state.get("project_syncs", {})
                if project_syncs:
                    for project_id, sync_info in project_syncs.items():
                        project_syncs_info[project_id] = {
                            "last_sync": sync_info.get("last_sync_human", "Неизвестно"),
                            "last_sync_iso": sync_info.get("last_sync", "")
                        }
                
                # Информация о полной перестройке
                rebuild_schedule = state.get("rebuild_schedule", {})
                if rebuild_schedule:
                    interval_days = load_config().get('sync', {}).get('full_rebuild_interval_days', 30)
                    interval_seconds = interval_days * 24 * 3600
                    current_time = datetime.utcnow()
                    
                    for project_id, info in rebuild_schedule.items():
                        try:
                            last_rebuild_str = info.get("last_full_rebuild")
                            if last_rebuild_str:
                                last_rebuild = datetime.fromisoformat(last_rebuild_str.replace('Z', '+00:00'))
                                time_diff = current_time - last_rebuild.replace(tzinfo=None)
                                seconds_since = time_diff.total_seconds()
                                
                                days_since_precise = seconds_since / (24 * 3600)
                                seconds_until_rebuild = max(0, interval_seconds - seconds_since)
                                days_until_rebuild_precise = seconds_until_rebuild / (24 * 3600)
                                
                                rebuild_info[project_id] = {
                                    "last_full_rebuild": last_rebuild.strftime("%Y-%m-%d %H:%M:%S UTC"),
                                    "days_since_rebuild": round(days_since_precise, 6),
                                    "days_until_rebuild": round(days_until_rebuild_precise, 6),
                                    "seconds_since_rebuild": int(seconds_since),
                                    "seconds_until_rebuild": int(seconds_until_rebuild),
                                    "rebuild_needed": seconds_since >= interval_seconds
                                }
                        except Exception as e:
                            logger.error(f"Ошибка обработки информации о перестройке {project_id}: {e}")
        
        force_sync_info = {}
        if sync_orchestrator.force_sync_running:
            elapsed_time = datetime.utcnow() - sync_orchestrator.force_sync_start_time
            force_sync_info = {
                "running": True,
                "start_time": sync_orchestrator.force_sync_start_time.isoformat(),
                "elapsed_seconds": int(elapsed_time.total_seconds())
            }
        elif sync_orchestrator.force_sync_status:
            force_sync_info = {
                "running": False,
                "status": sync_orchestrator.force_sync_status,
                "last_run": sync_orchestrator.force_sync_start_time.isoformat() if sync_orchestrator.force_sync_start_time else None
            }
        
        return {
            "status": "успех",
            "periodic_sync": {
                "running": sync_orchestrator.running,
                "last_sync": last_sync,
                "sync_interval": f"Каждые {sync_orchestrator.state_manager.periodic_interval_hours} часов",
            },
            "project_syncs": project_syncs_info,  # НОВОЕ: информация по каждому проекту
            "force_sync": force_sync_info,
            "full_rebuild": {
                "enabled": True,
                "scheduler_running": getattr(sync_orchestrator, 'rebuild_scheduler_running', False),
                "interval_days": load_config().get('sync', {}).get('full_rebuild_interval_days', 30),
                "check_interval": f"Каждые {sync_orchestrator.state_manager.rebuild_check_interval_hours} ч",
                "projects": rebuild_info
            },
            "external_api": sync_orchestrator.external_api_base
        }
    except Exception as e:
        logger.error(f"Ошибка получения статуса синхронизации: {e}")
        raise HTTPException(status_code=500, detail=str(e))

@app.post("/sync/stop", response_model=UniversalResponse)
async def stop_sync() -> UniversalResponse:
    """Остановить периодическую синхронизацию"""
    try:
        sync_orchestrator.stop()
        return UniversalResponse(
            status="успех",
            message="Периодическая синхронизация остановлена"
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.post("/sync/start", response_model=UniversalResponse)
async def start_sync() -> UniversalResponse:
    """Запустить периодическую синхронизацию"""
    try:
        await sync_orchestrator.start_periodic_sync()
        return UniversalResponse(
            status="успех",
            message="Периодическая синхронизация запущена"
        )
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))
