# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
StatusReporter — extracted from agent.py (PR 5).

Pure read-only aggregation of agent status, health, metrics,
bus status, mesh status, retriever status, and K8s probes.
"""

import logging
from typing import Optional

from .security import SecureSession, TrustLevel

logger = logging.getLogger(__name__)


class StatusReporter:
    """Aggregates agent status, health, metrics, and probe endpoints."""

    def __init__(self, agent_ref):
        self._agent = agent_ref

    def get_status(self) -> dict:
        """Get agent status."""
        agent = self._agent
        total_tools = len(agent.tools.tools)
        try:
            owner_session = SecureSession("_status", "cli")
            owner_session.set_trust_level(TrustLevel.OWNER)
            filtered, _skills = agent._tool_executor.get_allowed_tools(owner_session)
            tool_count = len(filtered)
        except Exception:
            tool_count = total_tools

        return {
            "name": agent.config.agent.name,
            "provider": agent.provider.name,
            "memory_entries": len(agent.memory.memories) if agent.memory else 0,
            "skills_loaded": len(agent.skills.skills),
            "tools_available": tool_count,
            "tools_registered": total_tools,
            "scheduled_tasks": len(agent.scheduler.tasks) if agent.scheduler else 0,
            "security_mode": agent.security_mode.value,
            "active_sessions": len(agent.sessions.get_all_sessions()),
            "model_router": ("active" if agent._provider_manager.model_router else "inactive"),
        }

    def get_health_status(self, include_resources: bool = True) -> dict:
        """Full health report as a plain dict."""
        return self._agent.health.check_health(
            include_resources=include_resources,
            use_cache=True,
        ).to_dict()

    def get_metrics_summary(
        self,
        tool_name: Optional[str] = None,
        include_llm: bool = True,
        include_tools: bool = True,
        include_alerts: bool = True,
    ) -> dict:
        """Return aggregated metrics as a plain dict."""
        agent = self._agent
        if tool_name is not None:
            tm = agent.metrics.get_tool_metrics(tool_name)
            return tm.to_dict() if tm else {"tool_name": tool_name, "total_calls": 0}

        result: dict = {}

        if include_tools:
            result["tools"] = agent.metrics.get_tool_summary()

        if include_llm:
            llm_summary = agent.metrics.get_llm_summary()
            result["llm"] = llm_summary
            result["total_cost_usd"] = llm_summary.get("total_cost_usd", 0.0)
            result["total_tokens"] = llm_summary.get("total_tokens", 0)

        if include_alerts:
            result["alerts"] = [a.to_dict() for a in agent.metrics.get_alerts()]

        result["timestamp"] = __import__("datetime").datetime.now().isoformat()
        return result

    def get_bus_status(self) -> dict:
        """Return a structured dict describing the current SkillBus state."""
        agent = self._agent
        dlq_stats = {}
        try:
            dlq_stats = agent.bus.get_dead_letter_stats()
        except Exception:
            pass

        return {
            "running": agent.bus._running,
            "registered_skills": agent.bus.list_skills(),
            "subscription_count": len(agent.bus._subscriptions),
            "shared_state_keys": agent.bus.state.keys(),
            "dead_letter": dlq_stats,
        }

    def get_mesh_status(self) -> dict:
        """Return a dict describing current mesh state."""
        agent = self._agent
        if not agent.mesh_gateway:
            return {"enabled": False, "running": False}

        gw = agent.mesh_gateway
        trust_status = {}
        if gw.trust_manager:
            try:
                trust_status = gw.trust_manager.get_status()
            except Exception:
                pass

        memory_status = {}
        if gw.memory_bridge:
            try:
                memory_status = gw.memory_bridge.get_status()
            except Exception:
                pass

        return {
            "enabled": True,
            "running": gw._running,
            "host": gw.host,
            "port": gw.port,
            "node_id": gw.config.get("node_id", "")[:8] + "...",
            "node_name": gw.config.get("node_name", "familiar"),
            "connected_nodes": len(gw.nodes),
            "peer_gateways": len(gw.peer_gateways),
            "discovery_active": gw.discovery is not None,
            "trust": trust_status,
            "memory": memory_status,
            "remote_agents": len(
                [
                    a
                    for a in agent.orchestrator.registry.get_all()
                    if getattr(a, "_metadata", {}).get("remote")
                ]
            ),
        }

    def get_retriever_status(self) -> dict:
        """Return a structured dict describing the current RAG retriever state."""
        agent = self._agent
        provider_name = "unknown"
        try:
            raw = getattr(agent.retriever._embedding, "_p", None)
            if raw:
                provider_name = getattr(raw, "name", type(raw).__name__)
        except Exception:
            pass

        return {
            "provider": provider_name,
            "doc_count": agent.retriever.count,
            "vector_store": type(agent.retriever._store).__name__,
            "config": {
                "top_k": agent.retriever.config.top_k,
                "min_score": agent.retriever.config.min_score,
                "chunk_size": agent.retriever.config.chunk_size,
                "chunk_overlap": agent.retriever.config.chunk_overlap,
                "max_tokens": agent.retriever.config.max_tokens,
            },
        }

    def mark_ready(self) -> None:
        """Explicitly mark the agent as ready for traffic."""
        self._agent.health.mark_startup_complete()
        logger.info("Agent marked ready (readiness probe will return ready=True)")

    def liveness(self) -> dict:
        """Liveness probe."""
        return self._agent.health.liveness_check()

    def readiness(self) -> dict:
        """Readiness probe."""
        return self._agent.health.readiness_check()

    def startup_probe(self) -> dict:
        """Startup probe."""
        return self._agent.health.startup_check()
