"""
Utility functions and helpers for Toxo.
"""

import sys
import json
import zipfile
from pathlib import Path
from typing import Dict, Any, List, Tuple

from .logger import get_logger, setup_logging
from .exceptions import ToxoError, TrainingError, MemoryError, ConfigError
from .validation import validate_config, validate_training_data


def get_version() -> str:
    """Get the current version of TOXO package."""
    # Prefer installed package metadata; fallback to toxo.__version__.
    try:
        from importlib.metadata import version as _pkg_version
        return _pkg_version("toxo")
    except Exception:
        try:
            from .. import __version__ as _v
            return _v
        except Exception:
            return "unknown"


def check_dependencies() -> Dict[str, Any]:
    """
    Check if dependencies are available and recommend use-case extras.

    This is intentionally lightweight (import checks only) and is used by `toxo check`.
    """
    deps: Dict[str, Any] = {
        "python_version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}",
        "python_compatible": sys.version_info >= (3, 9),
        "required_packages": {},
        "optional_packages": {},
        "recommended_extras": {},  # extra -> {"missing": [...], "why": "...", "system": [...]}
        "status": "unknown",
    }

    required: List[Tuple[str, str]] = [
        ("google.generativeai", "google-generativeai"),
        ("numpy", "numpy"),
        ("requests", "requests"),
        ("tqdm", "tqdm"),
        ("pydantic", "pydantic"),
        ("yaml", "pyyaml"),
        ("loguru", "loguru"),
    ]
    for mod, pkg in required:
        try:
            __import__(mod)
            deps["required_packages"][pkg] = "Available"
        except ImportError:
            deps["required_packages"][pkg] = "Missing"

    # Use-case extras: keep this map aligned with `pyproject.toml`/`setup.py`.
    extras: Dict[str, Dict[str, Any]] = {
        "vision": {
            "why": "Multimodal PDFs/images (Gemini): PDF rendering + image/OCR helpers",
            "modules": [("pdf2image", "pdf2image"), ("fitz", "PyMuPDF"), ("openpyxl", "openpyxl"), ("PIL", "pillow")],
            "system_darwin": ["brew install poppler  # required for pdf2image"],
        },
        "rag": {
            "why": "RAG / vector store / retrieval",
            "modules": [("sqlalchemy", "sqlalchemy"), ("chromadb", "chromadb"), ("sklearn", "scikit-learn")],
            "system_darwin": [],
        },
        "enterprise": {
            "why": "Monitoring/metrics/caching helpers",
            "modules": [("psutil", "psutil"), ("prometheus_client", "prometheus-client")],
            "system_darwin": [],
        },
        "distributed": {
            "why": "Distributed/Redis-backed features",
            "modules": [("redis", "redis")],
            "system_darwin": [],
        },
        "auth": {
            "why": "JWT auth helpers",
            "modules": [("jwt", "PyJWT"), ("bcrypt", "bcrypt")],
            "system_darwin": [],
        },
        "payments": {
            "why": "Payments/subscriptions (Razorpay)",
            "modules": [("razorpay", "razorpay"), ("dotenv", "python-dotenv")],
            "system_darwin": [],
        },
    }

    # Optional packages section remains a simple view for backwards compatibility.
    # We also add all extra modules into optional_packages.
    for extra, spec in extras.items():
        missing_pkgs: List[str] = []
        for mod, pkg in spec["modules"]:
            try:
                __import__(mod)
                deps["optional_packages"][pkg] = "Available"
            except ImportError:
                deps["optional_packages"][pkg] = "Optional"
                missing_pkgs.append(pkg)
        if missing_pkgs:
            system: List[str] = []
            if sys.platform.startswith("darwin"):
                system = list(spec.get("system_darwin", []))
            deps["recommended_extras"][extra] = {
                "missing": missing_pkgs,
                "why": spec["why"],
                "system": system,
            }

    missing_required = [p for p, s in deps["required_packages"].items() if s == "Missing"]
    deps["status"] = "All requirements satisfied" if not missing_required else f"Missing: {missing_required}"
    return deps


def print_dependency_status() -> None:
    """Print a formatted dependency status report."""
    deps = check_dependencies()
    print("TOXO Dependency Check")
    print("=" * 40)
    print(f"Python Version: {deps['python_version']}")
    print(f"Status: {deps['status']}")

    rec = deps.get("recommended_extras") or {}
    if rec:
        print("")
        print("Recommended optional installs (choose by use case):")
        for extra, info in rec.items():
            why = info.get("why", "")
            missing = ", ".join(info.get("missing", []))
            print(f"  - toxo[{extra}]: {why}")
            if missing:
                print(f"    Missing: {missing}")
            system = info.get("system") or []
            for line in system:
                print(f"    System: {line}")


def validate_toxo_file(file_path: str) -> Dict[str, Any]:
    """Validate if a file is a proper .toxo file."""
    result = {"valid": False, "errors": [], "warnings": [], "info": {}}
    fp = Path(file_path)
    if not fp.exists():
        result["errors"].append("File does not exist")
        return result
    if fp.suffix.lower() != '.toxo':
        result["errors"].append("File must have .toxo extension")
        return result
    try:
        with zipfile.ZipFile(fp, 'r') as z:
            names = z.namelist()
            if "manifest.json" not in names:
                result["errors"].append("Missing manifest.json")
            try:
                m = json.loads(z.read("manifest.json").decode('utf-8'))
                pkg = m.get("package_info") or m
                result["info"] = {
                    "name": pkg.get("name", "Unknown"),
                    "domain": m.get("domain", pkg.get("domain", "Unknown")),
                    "version": m.get("version", pkg.get("version", "Unknown")),
                    "file_count": len(names),
                    "file_size": f"{fp.stat().st_size / 1024:.1f} KB"
                }
            except Exception:
                result["info"] = {"file_count": len(names)}
            if not result["errors"]:
                result["valid"] = True
    except zipfile.BadZipFile:
        result["errors"].append("File is not a valid ZIP archive")
    except Exception as e:
        result["errors"].append(str(e))
    return result


def print_toxo_info(file_path: str) -> None:
    """Print information about a .toxo file."""
    v = validate_toxo_file(file_path)
    print(f"TOXO File Information: {Path(file_path).name}")
    print("=" * 50)
    if v["valid"]:
        print("Valid TOXO file")
        for k, val in v.get("info", {}).items():
            print(f"  {k}: {val}")
    else:
        print("Invalid TOXO file")
        for e in v["errors"]:
            print(f"  Error: {e}")


def get_sample_usage() -> str:
    """Get sample usage code for TOXO."""
    return '''from toxo import ToxoLayer
layer = ToxoLayer.load("your_expert_model.toxo")
layer.setup_api_key("your_gemini_api_key_here")
response = layer.query_sync("Your question here")
'''


def get_help_text() -> str:
    """Get help text for TOXO usage."""
    return "TOXO - Smart Layer for CALM. See https://toxotune.com"


__all__ = [
    "get_version",
    "check_dependencies",
    "print_dependency_status",
    "validate_toxo_file",
    "print_toxo_info",
    "get_sample_usage",
    "get_help_text",
    "get_logger",
    "setup_logging",
    "ToxoError",
    "TrainingError", 
    "MemoryError",
    "ConfigError",
    "validate_config",
    "validate_training_data",
] 