"""SOAGILA MCP Server — Main entry point.

Runs as a subprocess spawned by the VS Code extension.
Communicates with Claude Code via MCP protocol over stdio.
"""

import asyncio
import logging
import sys

from mcp.server import Server
from mcp.server.stdio import stdio_server

from soagila.config import get_settings

# Configure logging to stderr (stdout is reserved for MCP protocol)
logging.basicConfig(
    level=logging.INFO,
    format="[SOAGILA] %(asctime)s %(levelname)s %(name)s: %(message)s",
    stream=sys.stderr,
)
logger = logging.getLogger("soagila")

# Create MCP server instance
app = Server("soagila-memory")


async def initialize():
    """Initialize SOAGILA subsystems."""
    settings = get_settings()
    logger.info(f"SOAGILA for Code v{settings.app_version}")
    logger.info(f"Project CWD: {settings.project_cwd}")
    logger.info(f"Tier: {settings.tier}")

    # Initialize SQLite database
    from soagila.db.sqlite_init import init_database
    await init_database()
    logger.info("SQLite database initialized")

    # Initialize global inheritance database
    if settings.inheritance_enabled:
        from soagila.db.sqlite_init import init_global_database
        await init_global_database()
        logger.info("Global inheritance database initialized")

    # Check project limit
    from soagila.project_manager import check_project_limit
    allowed, msg = check_project_limit()
    if not allowed:
        logger.warning(f"Project limit reached: {msg}")
    else:
        logger.info(f"Project access: {msg}")

    # Enforce retention limits (expire old memories)
    from soagila.project_manager import enforce_retention_limit
    expired = await enforce_retention_limit()
    if expired > 0:
        logger.info(f"Retention enforcement: {expired} memories expired")

    # Load persisted encryption keys
    from soagila.core.encryption.simulated_he import get_encryption_engine
    engine = get_encryption_engine()
    await engine.load_persisted_keys()
    logger.info("Encryption keys loaded")

    # Load IMA self-learning metrics (persisted thresholds)
    from soagila.core.ima.self_learning import load_metrics as load_ima_metrics
    await load_ima_metrics()
    logger.info("IMA self-learning metrics loaded")

    # Register MCP tools
    from soagila.tools import register_all_tools
    register_all_tools(app)
    logger.info("MCP tools registered")

    # Preload embedding model in background
    asyncio.create_task(_preload_embedding())

    # Start background scheduler (decay + promotion + auto-backup)
    asyncio.create_task(_background_scheduler())
    logger.info("Background scheduler started (decay + promotion every 5min)")

    # Start telemetry collector
    if settings.telemetry_enabled:
        from soagila.core.telemetry.collector import set_platform, track, start_flush_timer
        set_platform("vscode")
        track("session_start", "lifecycle", {"tier": settings.tier})
        await start_flush_timer()
        logger.info("Telemetry collector started")

    # Start Cross-Agent Protocol bridge (HTTP for peer discovery)
    await _start_agent_bridge()


async def _start_agent_bridge():
    """Start the Cross-Agent Protocol HTTP bridge for peer communication."""
    try:
        from soagila.core.cap.http_agent_bridge import start_bridge
        from soagila.core.cap.discovery import start_discovery
        from soagila.config import get_project_hash, get_settings
        from pathlib import Path

        settings = get_settings()
        port = await start_bridge()

        await start_discovery(
            product_type="vscode",
            port=port,
            project_hash=get_project_hash(),
            project_name=Path(settings.project_cwd).name,
            capabilities=["recall", "remember", "receipt", "status", "inspect",
                           "prime", "annihilate", "backup", "enterprise", "crossagent"],
            version=settings.app_version,
        )
        logger.info(f"Cross-Agent Protocol active on port {port}")
    except Exception as e:
        logger.warning(f"Cross-Agent Protocol failed to start: {e}")


async def _background_scheduler():
    """SOAGILA's autonomous background processes — decay, promotion, auto-backup."""
    await asyncio.sleep(60)  # Initial delay — let system stabilize
    while True:
        try:
            # 1. Decay cycle — Ebbinghaus forgetting curve
            from soagila.core.tcmg.decay_engine import run_decay_cycle
            decay_result = await run_decay_cycle()

            # 2. Promotion check — episodic clusters → semantic knowledge
            from soagila.core.tcmg.promotion_engine import run_promotion_check
            promo_result = await run_promotion_check("local")

            if decay_result.memories_decayed > 0 or promo_result.promotions_executed > 0:
                logger.info(
                    f"Background: {decay_result.memories_decayed} decayed, "
                    f"{promo_result.promotions_executed} promoted"
                )

            # 3. IMA self-learning: auto-tune thresholds + persist metrics
            from soagila.core.ima.self_learning import auto_tune_thresholds, persist_metrics
            adjustments = auto_tune_thresholds()
            await persist_metrics()
            if adjustments:
                logger.info(f"IMA self-learning: {len(adjustments)} thresholds tuned")

            # 4. Auto-backup (check interval)
            await _check_auto_backup()

            # 5. PMP: Predictive priming cycle
            from soagila.config import get_settings as _get_bg_settings
            _bg_settings = _get_bg_settings()
            if _bg_settings.pmp_enabled and _bg_settings.pmp_background_prime:
                try:
                    from soagila.core.pmp.predictor import refresh_patterns, predict_topics, persist_prediction_metrics
                    from soagila.core.pmp.primer import prime_for_context, check_if_primed

                    # Refresh pattern analysis
                    await refresh_patterns("local")

                    # Predict next likely topics
                    predictions = await predict_topics(
                        "local",
                        max_predictions=_bg_settings.pmp_prediction_depth,
                    )

                    if predictions and not await check_if_primed("local"):
                        hint = ", ".join(p.topic for p in predictions[:3])
                        await prime_for_context("local", hint, trigger="background_prediction")
                        logger.info(f"PMP: Background primed for: {hint}")

                    await persist_prediction_metrics()
                except Exception as e:
                    logger.warning(f"PMP background cycle error: {e}")

        except Exception as e:
            logger.warning(f"Background scheduler error: {e}")

        await asyncio.sleep(300)  # Every 5 minutes


async def _check_auto_backup():
    """Run auto-backup if interval has elapsed."""
    import os
    from datetime import datetime, timezone, timedelta
    from soagila.config import get_project_dir

    backup_path = os.environ.get("SOAGILA_BACKUP_PATH", "")
    auto_enabled = os.environ.get("SOAGILA_BACKUP_AUTO", "false").lower() == "true"
    interval_hours = int(os.environ.get("SOAGILA_BACKUP_INTERVAL", "24"))

    if not auto_enabled or not backup_path:
        return

    project_dir = get_project_dir()
    last_backup_file = project_dir / "last_backup.txt"

    now = datetime.now(timezone.utc)
    if last_backup_file.exists():
        last_str = last_backup_file.read_text().strip()
        try:
            last_time = datetime.fromisoformat(last_str)
            if now - last_time < timedelta(hours=interval_hours):
                return  # Not time yet
        except ValueError:
            pass  # Corrupted timestamp, proceed with backup

    try:
        from soagila.core.backup import create_backup
        result = await create_backup()
        last_backup_file.write_text(now.isoformat())
        logger.info(f"Auto-backup completed: {result.get('filename', 'unknown')}")
    except Exception as e:
        logger.warning(f"Auto-backup failed: {e}")


async def _preload_embedding():
    """Preload the sentence-transformers model (background task)."""
    try:
        logger.info("Loading embedding model (first run may download ~90MB)...")
        from soagila.core.tcmg.embedding_service import preload_model
        preload_model()
        logger.info("Embedding model loaded successfully")
    except Exception as e:
        logger.warning(f"Embedding model failed to load: {e}. Falling back to keyword matching.")


async def main():
    """Main entry point for the MCP server."""
    await initialize()

    logger.info("Starting MCP stdio server...")
    try:
        async with stdio_server() as (read_stream, write_stream):
            await app.run(read_stream, write_stream, app.create_initialization_options())
    finally:
        # Telemetry: session end + final flush
        try:
            from soagila.core.telemetry.collector import track, stop_flush_timer
            track("session_end", "lifecycle", {})
            await stop_flush_timer()
        except Exception:
            pass
        # Deregister from Cross-Agent Protocol on shutdown
        try:
            from soagila.core.cap.discovery import stop_discovery
            await stop_discovery()
        except Exception:
            pass


if __name__ == "__main__":
    asyncio.run(main())
