"""
Application FastAPI principale pour IPWatch
Point d'entrée du backend
"""
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from contextlib import asynccontextmanager
from pathlib import Path

from backend.app.core.config import config_manager
from backend.app.core.database import init_database, get_db
from backend.app.routers import ips_router, scan_router, websocket_router
from backend.app.routers import architecture as architecture_router
from backend.app.routers import config as config_router
from backend.app.routers import system as system_router
from backend.app.routers import tracking as tracking_router
from backend.app.routers import opnsense as opnsense_router
from backend.app.routers import services as services_router
from backend.app.services.scheduler import scan_scheduler
from backend.app.routers.scan import perform_scan


@asynccontextmanager
async def lifespan(app: FastAPI):
    """
    Gestionnaire du cycle de vie de l'application
    Initialise et nettoie les ressources
    """
    # Startup
    print("=== Démarrage IPWatch ===")

    # 1. Charger la configuration
    try:
        config = config_manager.load_config("./config.yaml")
        print(f"✓ Configuration chargée: {config.network.cidr}")
    except Exception as e:
        print(f"✗ Erreur chargement config: {e}")
        raise

    # 2. Initialiser la base de données
    try:
        init_database(config.database.path)
        print(f"✓ Base de données initialisée: {config.database.path}")
    except Exception as e:
        print(f"✗ Erreur initialisation DB: {e}")
        raise

    # 3. Démarrer le scheduler
    try:
        scan_scheduler.start()

        # Créer une session DB pour les scans planifiés
        from backend.app.core.database import SessionLocal

        async def scheduled_scan():
            """Wrapper pour scan planifié avec DB session"""
            db = SessionLocal()
            try:
                await perform_scan(db)
            finally:
                db.close()

        # Configurer les tâches périodiques
        scan_scheduler.add_ping_scan_job(
            scheduled_scan,
            interval_seconds=config.scan.ping_interval
        )

        scan_scheduler.add_port_scan_job(
            scheduled_scan,
            interval_seconds=config.scan.port_scan_interval
        )

        # Tâche de nettoyage historique
        async def cleanup_history():
            """Nettoie l'historique ancien"""
            from backend.app.models.ip import IPHistory
            from datetime import datetime, timedelta

            db = SessionLocal()
            try:
                cutoff = datetime.utcnow() - timedelta(hours=config.history.retention_hours)
                deleted = db.query(IPHistory).filter(IPHistory.timestamp < cutoff).delete()
                db.commit()
                print(f"Nettoyage historique: {deleted} entrées supprimées")
            finally:
                db.close()

        scan_scheduler.add_cleanup_job(cleanup_history, interval_hours=1)

        print("✓ Scheduler démarré")
    except Exception as e:
        print(f"✗ Erreur démarrage scheduler: {e}")

    print("=== IPWatch prêt ===\n")

    yield

    # Shutdown
    print("\n=== Arrêt IPWatch ===")
    scan_scheduler.stop()
    print("✓ Scheduler arrêté")


# Créer l'application FastAPI
app = FastAPI(
    title="IPWatch API",
    description="API backend pour IPWatch - Scanner réseau temps réel",
    version="1.0.0",
    lifespan=lifespan
)

# Configuration CORS pour le frontend
app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],  # À restreindre en production
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# Enregistrer les routers API
app.include_router(ips_router)
app.include_router(scan_router)
app.include_router(websocket_router)
app.include_router(config_router.router)
app.include_router(system_router.router)
app.include_router(tracking_router.router)
app.include_router(architecture_router.router)
app.include_router(opnsense_router.router)
app.include_router(services_router.router)

# Servir les ressources d'architecture
architecture_dir = Path("./architecture")
architecture_dir.mkdir(parents=True, exist_ok=True)
app.mount("/architecture", StaticFiles(directory=str(architecture_dir)), name="architecture")


@app.get("/health")
async def health_check():
    """Health check endpoint"""
    return {
        "status": "healthy",
        "scheduler": scan_scheduler.is_running
    }


# Servir les fichiers statiques du frontend
frontend_dist = Path(__file__).parent.parent.parent / "frontend" / "dist"

if frontend_dist.exists():
    # Monter les assets statiques
    app.mount("/assets", StaticFiles(directory=str(frontend_dist / "assets")), name="assets")

    # Monter les icônes partagées
    icons_dir = Path("./data/icons")
    icons_dir.mkdir(parents=True, exist_ok=True)
    app.mount("/icons", StaticFiles(directory=str(icons_dir)), name="icons")

    # Servir les fichiers statiques à la racine (favicon, manifest, etc.)
    @app.get("/favicon.ico")
    async def serve_favicon():
        favicon_path = frontend_dist / "favicon.ico"
        if favicon_path.exists():
            return FileResponse(favicon_path)
        return {"error": "Favicon non trouvée"}

    # Route racine pour servir index.html
    @app.get("/")
    async def serve_frontend():
        """Servir le frontend Vue"""
        index_file = frontend_dist / "index.html"
        if index_file.exists():
            return FileResponse(index_file)
        return {
            "name": "IPWatch API",
            "version": "1.0.0",
            "status": "running",
            "error": "Frontend non trouvé"
        }

    # Catch-all pour le routing Vue (SPA)
    @app.get("/{full_path:path}")
    async def catch_all(full_path: str):
        """Catch-all pour le routing Vue Router"""
        # Ne pas intercepter les routes API
        if full_path.startswith("api/") or full_path.startswith("ws"):
            return {"error": "Not found"}

        # Servir les fichiers statiques à la racine si présents
        if ".." not in full_path:
            candidate = (frontend_dist / full_path).resolve()
            if frontend_dist in candidate.parents and candidate.is_file():
                return FileResponse(candidate)

        # Servir index.html pour toutes les autres routes
        index_file = frontend_dist / "index.html"
        if index_file.exists():
            return FileResponse(index_file)
        return {"error": "Frontend non trouvé"}
else:
    @app.get("/")
    async def root():
        """Endpoint racine (mode développement sans frontend)"""
        return {
            "name": "IPWatch API",
            "version": "1.0.0",
            "status": "running",
            "note": "Frontend non buildé - utilisez le mode dev"
        }


if __name__ == "__main__":
    import uvicorn

    uvicorn.run(
        "backend.app.main:app",
        host="0.0.0.0",
        port=8080,
        reload=True
    )
