"""
InsAIts SDK - Readiness Checker
================================
System self-validation that checks whether all subsystems are
properly configured before the monitor processes messages.

Checks:
    1. License: API key validation status and tier
    2. Local embeddings: sentence-transformers model availability
    3. Ollama: Local LLM reachability (optional)
    4. Cloud: API backend reachability
    5. Anomaly engine: Detector initialization state
    6. Storage: Disk write access for caches and audit logs

Each check returns a structured result with status, detail, and
whether it is critical (blocks operation) or advisory (warning only).
"""

import logging
import os
import tempfile
import time
from pathlib import Path
from typing import Any, Dict, List, Optional

logger = logging.getLogger(__name__)


# Checks that MUST pass for the system to be considered ready
CRITICAL_CHECKS = frozenset({
    "license",
    "embeddings_local",
    "anomaly_engine",
    "storage",
})


def _make_check(
    status: str, detail: str, critical: bool = False
) -> Dict[str, Any]:
    """Create a standardized check result dict."""
    return {
        "status": status,
        "detail": detail,
        "critical": critical,
    }


class ReadinessChecker:
    """Validates that all InsAIts subsystems are operational.

    Usage:
        checker = ReadinessChecker(monitor_instance)
        result = checker.check()

        if result["ready"]:
            # All critical checks passed
            ...
        else:
            for name, check in result["checks"].items():
                if check["status"] == "fail":
                    logger.error(f"{name}: {check['detail']}")
    """

    def __init__(self, monitor: Any):
        """Initialize with a reference to the insAItsMonitor instance.

        Args:
            monitor: The insAItsMonitor instance to validate
        """
        self._monitor = monitor

    def check(self) -> Dict[str, Any]:
        """Run all readiness checks and return aggregated result.

        Returns:
            Dict with:
                ready (bool): True if all critical checks pass
                checks (Dict): Individual check results keyed by name
                warnings (List[str]): Non-critical issues
                errors (List[str]): Critical failures
                timestamp (float): When the check was performed
        """
        checks = {
            "license": self._check_license(),
            "embeddings_local": self._check_local_embeddings(),
            "ollama": self._check_ollama(),
            "cloud": self._check_cloud(),
            "anomaly_engine": self._check_anomaly_engine(),
            "storage": self._check_storage(),
        }

        warnings: List[str] = []
        errors: List[str] = []

        for name, result in checks.items():
            if result["status"] == "fail" and result.get("critical", False):
                errors.append(f"{name}: {result['detail']}")
            elif result["status"] == "warn":
                warnings.append(f"{name}: {result['detail']}")
            elif result["status"] == "fail":
                warnings.append(f"{name}: {result['detail']}")

        # System is ready if no critical errors
        ready = len(errors) == 0

        if ready:
            logger.info("InsAIts readiness check PASSED")
        else:
            logger.warning(
                "InsAIts readiness check FAILED: %s",
                "; ".join(errors),
            )

        return {
            "ready": ready,
            "checks": checks,
            "warnings": warnings,
            "errors": errors,
            "timestamp": time.time(),
        }

    def _check_license(self) -> Dict[str, Any]:
        """Check API key validation status and tier."""
        try:
            license_mgr = getattr(self._monitor, "license", None)
            if license_mgr is None:
                return _make_check(
                    "fail",
                    "LicenseManager not initialized",
                    critical=True,
                )

            tier = getattr(license_mgr, "tier", "anonymous")
            is_validated = getattr(license_mgr, "is_validated", False)
            api_key = getattr(license_mgr, "api_key", None)

            if api_key is None:
                return _make_check(
                    "warn",
                    "No API key configured. Running as anonymous "
                    "(50 msg/day limit). Register at "
                    "https://github.com/Nomadu27/InsAIts.API",
                    critical=False,
                )

            if is_validated:
                return _make_check(
                    "ok",
                    f"Validated. Tier: {tier}",
                    critical=False,
                )

            return _make_check(
                "warn",
                f"API key present but not yet validated. Tier: {tier}",
                critical=False,
            )

        except Exception as exc:
            return _make_check(
                "fail",
                f"License check error: {exc}",
                critical=True,
            )

    def _check_local_embeddings(self) -> Dict[str, Any]:
        """Check if local embedding model is loaded."""
        try:
            from . import embeddings

            if getattr(embeddings, "LOCAL_MODEL_AVAILABLE", False):
                return _make_check(
                    "ok",
                    "sentence-transformers model loaded "
                    "(BAAI/bge-small-en-v1.5, 384-dim)",
                    critical=False,
                )

            return _make_check(
                "warn",
                "Using synthetic embeddings (lower quality). "
                "Install sentence-transformers for better detection: "
                "pip install sentence-transformers",
                critical=False,
            )

        except Exception as exc:
            return _make_check(
                "fail",
                f"Embedding subsystem error: {exc}",
                critical=True,
            )

    def _check_ollama(self) -> Dict[str, Any]:
        """Check if Ollama local LLM is reachable."""
        try:
            from .local_llm import check_ollama_available, get_default_model

            if check_ollama_available():
                model = get_default_model()
                return _make_check(
                    "ok",
                    f"Ollama reachable. Default model: {model}",
                    critical=False,
                )

            return _make_check(
                "warn",
                "Ollama not running. Low-confidence detection and "
                "self-consistency checks will be disabled. "
                "Install: https://ollama.com",
                critical=False,
            )

        except ImportError:
            return _make_check(
                "warn",
                "Ollama module not available",
                critical=False,
            )
        except Exception as exc:
            return _make_check(
                "warn",
                f"Ollama check error: {exc}",
                critical=False,
            )

    def _check_cloud(self) -> Dict[str, Any]:
        """Check API backend reachability."""
        try:
            from .config import API_BASE_URL

            try:
                import requests

                response = requests.get(
                    f"{API_BASE_URL}/api/health",
                    timeout=5,
                )
                if response.status_code == 200:
                    return _make_check(
                        "ok",
                        f"API reachable at {API_BASE_URL}",
                        critical=False,
                    )
                return _make_check(
                    "warn",
                    f"API returned status {response.status_code}",
                    critical=False,
                )
            except ImportError:
                return _make_check(
                    "warn",
                    "requests not installed, cannot check cloud",
                    critical=False,
                )
            except Exception as exc:
                return _make_check(
                    "warn",
                    f"API unreachable: {exc}. Offline mode active.",
                    critical=False,
                )

        except Exception as exc:
            return _make_check(
                "warn",
                f"Cloud config error: {exc}",
                critical=False,
            )

    def _check_anomaly_engine(self) -> Dict[str, Any]:
        """Check detector initialization state."""
        try:
            detector = getattr(self._monitor, "detector", None)
            if detector is None:
                return _make_check(
                    "fail",
                    "AnomalyDetector not initialized",
                    critical=True,
                )

            premium = getattr(detector, "_premium_detector", None)
            adaptive = getattr(detector, "_adaptive_dict", None)
            anchor = getattr(detector, "_detect_anchor_drift", None)

            features = []
            features.append("fingerprint_mismatch")
            if premium is not None:
                features.append("premium_detection")
            if adaptive is not None:
                features.append("adaptive_dictionary")
            if anchor is not None:
                features.append("anchor_forensics")

            return _make_check(
                "ok",
                f"Active detectors: {', '.join(features)}",
                critical=False,
            )

        except Exception as exc:
            return _make_check(
                "fail",
                f"Anomaly engine error: {exc}",
                critical=True,
            )

    def _check_storage(self) -> Dict[str, Any]:
        """Check disk write access for caches and audit logs."""
        try:
            cache_dir = Path.home() / ".insaits"

            # Check if we can write to cache directory
            if cache_dir.exists():
                test_file = cache_dir / ".readiness_check"
                try:
                    test_file.write_text("ok")
                    test_file.unlink()
                    return _make_check(
                        "ok",
                        f"Cache directory writable: {cache_dir}",
                        critical=False,
                    )
                except (OSError, PermissionError) as exc:
                    return _make_check(
                        "warn",
                        f"Cache directory not writable: {exc}",
                        critical=False,
                    )
            else:
                # Try to create it
                try:
                    cache_dir.mkdir(parents=True, exist_ok=True)
                    return _make_check(
                        "ok",
                        f"Cache directory created: {cache_dir}",
                        critical=False,
                    )
                except (OSError, PermissionError) as exc:
                    return _make_check(
                        "warn",
                        f"Cannot create cache directory: {exc}",
                        critical=False,
                    )

        except Exception as exc:
            return _make_check(
                "warn",
                f"Storage check error: {exc}",
                critical=False,
            )
