"""
AIVA Startup Orchestrator - PM-034

Initializes all AIVA loops on startup.
Manages loop lifecycle and systemd registration.
"""

import os
import sys
import json
import logging
import asyncio
import signal
from datetime import datetime
from typing import Dict, List, Optional, Any
from dataclasses import dataclass, asdict
from pathlib import Path

# Configure logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)


@dataclass
class LoopStatus:
    """Status of a loop."""
    name: str
    running: bool
    interval_seconds: int
    last_execution: Optional[str]
    error: Optional[str] = None


@dataclass
class AIVAStatus:
    """Overall AIVA status."""
    started_at: str
    uptime_seconds: float
    loops: Dict[str, LoopStatus]
    overall_health: str  # healthy, degraded, unhealthy


class StartupOrchestrator:
    """
    Orchestrates AIVA startup and loop management.

    Initializes and manages:
    - Perception loop (500ms) - external event detection
    - Action loop (5s) - task execution
    - Reflection loop (5 min) - learning consolidation
    - Strategic loop (1 hour) - goal evaluation
    - Circadian loop (24 hours) - deep consolidation

    Usage:
        orchestrator = StartupOrchestrator()
        await orchestrator.init_aiva()
        await orchestrator.run_forever()
    """

    def __init__(
        self,
        config_path: Optional[str] = None,
        log_dir: str = "logs"
    ):
        """
        Initialize the startup orchestrator.

        Args:
            config_path: Path to configuration file
            log_dir: Directory for logs
        """
        self.config_path = config_path
        self.log_dir = Path(log_dir)
        self.log_dir.mkdir(parents=True, exist_ok=True)

        # Loop instances
        self.perception_loop = None
        self.action_loop = None
        self.reflection_loop = None
        self.strategic_loop = None
        self.circadian_loop = None

        # Core components
        self.memory_bridge = None
        self.permission_manager = None
        self.rank_tracker = None
        self.skill_registry = None
        self.task_consumer = None
        self.monitoring_dashboard = None

        # State
        self._running = False
        self._started_at: Optional[datetime] = None
        self._shutdown_event: Optional[asyncio.Event] = None

        logger.info("StartupOrchestrator initialized")

    async def init_aiva(self) -> bool:
        """
        Initialize all AIVA components and loops.

        Returns:
            True if initialization successful
        """
        logger.info("=" * 50)
        logger.info("AIVA STARTUP SEQUENCE INITIATED")
        logger.info("=" * 50)

        self._started_at = datetime.utcnow()
        self._shutdown_event = asyncio.Event()

        try:
            # Phase 1: Initialize core components
            logger.info("[1/5] Initializing core components...")
            await self._init_core_components()

            # Phase 2: Initialize loops
            logger.info("[2/5] Initializing loops...")
            await self._init_loops()

            # Phase 3: Verify connections
            logger.info("[3/5] Verifying connections...")
            await self._verify_connections()

            # Phase 4: Start loops
            logger.info("[4/5] Starting loops...")
            await self._start_all_loops()

            # Phase 5: Register with systemd (if applicable)
            logger.info("[5/5] Registering with system...")
            await self._register_systemd()

            self._running = True

            logger.info("=" * 50)
            logger.info("AIVA STARTUP COMPLETE")
            logger.info(f"Started at: {self._started_at.isoformat()}")
            logger.info("=" * 50)

            return True

        except Exception as e:
            logger.error(f"AIVA startup failed: {e}")
            return False

    async def _init_core_components(self) -> None:
        """Initialize core AIVA components."""
        # Import components (deferred to avoid circular imports)
        try:
            from .memory_bridge import MemoryBridge
            self.memory_bridge = MemoryBridge()
            self.memory_bridge.connect_all()
            logger.info("  - MemoryBridge initialized")
        except Exception as e:
            logger.warning(f"  - MemoryBridge failed: {e}")

        try:
            from .permission_manager import PermissionManager
            self.permission_manager = PermissionManager()
            logger.info("  - PermissionManager initialized")
        except Exception as e:
            logger.warning(f"  - PermissionManager failed: {e}")

        try:
            from .rank_tracker import RankTracker
            self.rank_tracker = RankTracker()
            logger.info(f"  - RankTracker initialized (Rank: {self.rank_tracker.current_rank.name})")
        except Exception as e:
            logger.warning(f"  - RankTracker failed: {e}")

        try:
            from .skill_registry import SkillRegistry
            self.skill_registry = SkillRegistry(
                permission_manager=self.permission_manager,
                rank_tracker=self.rank_tracker
            )
            logger.info(f"  - SkillRegistry initialized ({len(self.skill_registry.skills)} skills)")
        except Exception as e:
            logger.warning(f"  - SkillRegistry failed: {e}")

        try:
            from .task_consumer import TaskConsumer
            self.task_consumer = TaskConsumer(
                skill_registry=self.skill_registry,
                permission_manager=self.permission_manager
            )
            logger.info("  - TaskConsumer initialized")
        except Exception as e:
            logger.warning(f"  - TaskConsumer failed: {e}")

        try:
            from .monitoring_dashboard import MonitoringDashboard
            self.monitoring_dashboard = MonitoringDashboard(
                task_consumer=self.task_consumer,
                rank_tracker=self.rank_tracker,
                memory_bridge=self.memory_bridge
            )
            logger.info("  - MonitoringDashboard initialized")
        except Exception as e:
            logger.warning(f"  - MonitoringDashboard failed: {e}")

    async def _init_loops(self) -> None:
        """Initialize all loops."""
        try:
            from .reflection_loop import ReflectionLoop
            self.reflection_loop = ReflectionLoop(
                memory_bridge=self.memory_bridge,
                interval_seconds=300  # 5 minutes
            )
            logger.info("  - ReflectionLoop initialized (5 min)")
        except Exception as e:
            logger.warning(f"  - ReflectionLoop failed: {e}")

        try:
            from .strategic_loop import StrategicLoop
            self.strategic_loop = StrategicLoop(
                rank_tracker=self.rank_tracker,
                monitoring_dashboard=self.monitoring_dashboard,
                interval_seconds=3600  # 1 hour
            )
            logger.info("  - StrategicLoop initialized (1 hour)")
        except Exception as e:
            logger.warning(f"  - StrategicLoop failed: {e}")

        try:
            from .circadian_loop import CircadianLoop
            self.circadian_loop = CircadianLoop(
                memory_bridge=self.memory_bridge,
                rank_tracker=self.rank_tracker,
                reflection_loop=self.reflection_loop,
                strategic_loop=self.strategic_loop,
                interval_seconds=86400  # 24 hours
            )
            logger.info("  - CircadianLoop initialized (24 hours)")
        except Exception as e:
            logger.warning(f"  - CircadianLoop failed: {e}")

    async def _verify_connections(self) -> None:
        """Verify all connections are working."""
        if self.memory_bridge:
            status = self.memory_bridge.connect_all()
            for backend, connected in status.items():
                status_str = "OK" if connected else "FAILED"
                logger.info(f"  - {backend}: {status_str}")

    async def _start_all_loops(self) -> None:
        """Start all loops."""
        loops = [
            ("reflection", self.reflection_loop),
            ("strategic", self.strategic_loop),
            ("circadian", self.circadian_loop)
        ]

        for name, loop in loops:
            if loop:
                try:
                    await loop.start()
                    logger.info(f"  - {name} loop: STARTED")
                except Exception as e:
                    logger.error(f"  - {name} loop: FAILED ({e})")

    async def _register_systemd(self) -> None:
        """Register with systemd for service management."""
        # Write PID file
        pid_file = self.log_dir / "aiva.pid"
        with open(pid_file, "w") as f:
            f.write(str(os.getpid()))
        logger.info(f"  - PID file written: {pid_file}")

        # Notify systemd (if running as service)
        try:
            import sdnotify
            notifier = sdnotify.SystemdNotifier()
            notifier.notify("READY=1")
            logger.info("  - Systemd notified: READY")
        except ImportError:
            logger.debug("  - sdnotify not available (not running as systemd service)")

    async def shutdown(self) -> None:
        """Gracefully shutdown AIVA."""
        logger.info("=" * 50)
        logger.info("AIVA SHUTDOWN SEQUENCE INITIATED")
        logger.info("=" * 50)

        self._running = False

        # Stop loops
        loops = [
            ("reflection", self.reflection_loop),
            ("strategic", self.strategic_loop),
            ("circadian", self.circadian_loop)
        ]

        for name, loop in loops:
            if loop:
                try:
                    await loop.stop()
                    logger.info(f"  - {name} loop: STOPPED")
                except Exception as e:
                    logger.error(f"  - {name} loop stop failed: {e}")

        # Signal shutdown event
        if self._shutdown_event:
            self._shutdown_event.set()

        # Remove PID file
        pid_file = self.log_dir / "aiva.pid"
        if pid_file.exists():
            pid_file.unlink()

        logger.info("AIVA SHUTDOWN COMPLETE")

    async def run_forever(self) -> None:
        """Run AIVA until shutdown signal."""
        if not self._running:
            logger.error("AIVA not initialized, call init_aiva() first")
            return

        # Setup signal handlers
        loop = asyncio.get_event_loop()
        for sig in (signal.SIGINT, signal.SIGTERM):
            loop.add_signal_handler(
                sig,
                lambda: asyncio.create_task(self.shutdown())
            )

        logger.info("AIVA running, press Ctrl+C to stop...")

        # Wait for shutdown
        await self._shutdown_event.wait()

    def get_status(self) -> AIVAStatus:
        """Get current AIVA status."""
        uptime = 0.0
        if self._started_at:
            uptime = (datetime.utcnow() - self._started_at).total_seconds()

        loops = {}

        if self.reflection_loop:
            stats = self.reflection_loop.get_stats()
            loops["reflection"] = LoopStatus(
                name="Reflection Loop",
                running=stats.get("is_running", False),
                interval_seconds=300,
                last_execution=None
            )

        if self.strategic_loop:
            stats = self.strategic_loop.get_stats()
            loops["strategic"] = LoopStatus(
                name="Strategic Loop",
                running=stats.get("is_running", False),
                interval_seconds=3600,
                last_execution=None
            )

        if self.circadian_loop:
            stats = self.circadian_loop.get_stats()
            loops["circadian"] = LoopStatus(
                name="Circadian Loop",
                running=stats.get("is_running", False),
                interval_seconds=86400,
                last_execution=stats.get("last_consolidation")
            )

        # Determine overall health
        running_count = sum(1 for l in loops.values() if l.running)
        if running_count == len(loops):
            health = "healthy"
        elif running_count > 0:
            health = "degraded"
        else:
            health = "unhealthy"

        return AIVAStatus(
            started_at=self._started_at.isoformat() if self._started_at else "",
            uptime_seconds=uptime,
            loops={k: asdict(v) for k, v in loops.items()},
            overall_health=health
        )

    def get_summary(self) -> Dict:
        """Get a summary for display."""
        status = self.get_status()
        return {
            "started_at": status.started_at,
            "uptime_hours": status.uptime_seconds / 3600,
            "overall_health": status.overall_health,
            "loops_running": sum(1 for l in status.loops.values() if l.get("running", False)),
            "loops_total": len(status.loops),
            "current_rank": self.rank_tracker.current_rank.name if self.rank_tracker else "Unknown"
        }


# Singleton instance
_orchestrator: Optional[StartupOrchestrator] = None


def get_orchestrator() -> StartupOrchestrator:
    """Get or create singleton StartupOrchestrator."""
    global _orchestrator
    if _orchestrator is None:
        _orchestrator = StartupOrchestrator()
    return _orchestrator


async def main():
    """Main entry point for AIVA."""
    orchestrator = StartupOrchestrator()

    # Initialize AIVA
    success = await orchestrator.init_aiva()
    if not success:
        logger.error("AIVA initialization failed, exiting")
        sys.exit(1)

    # Print status
    summary = orchestrator.get_summary()
    logger.info(f"AIVA Status: {json.dumps(summary, indent=2)}")

    # Run until shutdown
    await orchestrator.run_forever()


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