# 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

"""
Marketplace — Skill Package Validator and Installer.

Skill package format (JSON):
{
    "schema_version": "1.0",
    "type": "skill",
    "metadata": {
        "id": "my_skill",
        "name": "My Custom Skill",
        "version": "1.0.0",
        "author": "...",
        "description": "...",
        "category": "productivity",
        "familiar_version": ">=1.14.52"
    },
    "tools": [
        {
            "name": "my_tool",
            "description": "Does something",
            "input_schema": {...},
            "category": "my_skill"
        }
    ],
    "env_vars": ["MY_SKILL_API_KEY"],
    "setup_instructions": "..."
}

Skill packages register tools in the custom skill registry for
dynamic loading by the tool executor.
"""

import json
import logging

from ..core.paths import DATA_DIR

logger = logging.getLogger(__name__)

CUSTOM_SKILLS_DIR = DATA_DIR / "custom_skills"

# Registry for dynamically installed skill tools
CUSTOM_SKILL_TOOLS: dict[str, list[dict]] = {}


def validate_skill_package(data: dict) -> list[str]:
    """Validate a skill package. Returns list of error strings (empty = valid)."""
    errors = []

    if data.get("type") != "skill":
        errors.append(f"Expected type 'skill', got '{data.get('type', '')}'")

    meta = data.get("metadata", {})
    if not meta:
        errors.append("Missing 'metadata' section")
    else:
        for field in ("id", "name", "version"):
            if not meta.get(field):
                errors.append(f"Missing metadata.{field}")

    tools = data.get("tools", [])
    if not tools:
        errors.append("No tools defined")
    else:
        for i, tool in enumerate(tools):
            if not tool.get("name"):
                errors.append(f"Tool {i}: missing 'name'")
            if not tool.get("description"):
                errors.append(f"Tool {i}: missing 'description'")
            if not tool.get("input_schema"):
                errors.append(f"Tool {i}: missing 'input_schema'")

    return errors


def install_skill_package(data: dict) -> str:
    """Install a skill package. Returns status message."""
    errors = validate_skill_package(data)
    if errors:
        return "Skill validation failed:\n" + "\n".join(f"  - {e}" for e in errors)

    meta = data.get("metadata", {})
    skill_id = meta["id"]

    CUSTOM_SKILLS_DIR.mkdir(parents=True, exist_ok=True)

    target = CUSTOM_SKILLS_DIR / f"{skill_id}.json"
    existing = target.exists()

    target.write_text(json.dumps(data, indent=2))

    # Register tools in memory
    tools = data.get("tools", [])
    CUSTOM_SKILL_TOOLS[skill_id] = tools

    action = "Updated" if existing else "Installed"
    return f"{action} skill '{meta.get('name', skill_id)}' v{meta.get('version', '?')} ({len(tools)} tools)"


def uninstall_skill_package(skill_id: str) -> str:
    """Uninstall a custom skill package."""
    target = CUSTOM_SKILLS_DIR / f"{skill_id}.json"
    if not target.exists():
        return f"Skill '{skill_id}' not found."

    target.unlink()
    CUSTOM_SKILL_TOOLS.pop(skill_id, None)

    return f"Uninstalled skill '{skill_id}'."


def list_skill_packages() -> list[dict]:
    """List installed custom skill packages."""
    if not CUSTOM_SKILLS_DIR.exists():
        return []

    packages = []
    for f in sorted(CUSTOM_SKILLS_DIR.glob("*.json")):
        try:
            data = json.loads(f.read_text())
            meta = data.get("metadata", {})
            tools = data.get("tools", [])
            packages.append(
                {
                    "id": meta.get("id", f.stem),
                    "name": meta.get("name", f.stem),
                    "version": meta.get("version", "unknown"),
                    "tools_count": len(tools),
                    "file": str(f),
                }
            )
        except Exception:
            packages.append({"id": f.stem, "name": f.stem, "version": "error", "file": str(f)})

    return packages


def load_custom_skills():
    """Load all custom skill packages from disk into CUSTOM_SKILL_TOOLS."""
    if not CUSTOM_SKILLS_DIR.exists():
        return

    for f in CUSTOM_SKILLS_DIR.glob("*.json"):
        try:
            data = json.loads(f.read_text())
            meta = data.get("metadata", {})
            skill_id = meta.get("id", f.stem)
            tools = data.get("tools", [])
            CUSTOM_SKILL_TOOLS[skill_id] = tools
            logger.debug("Loaded custom skill: %s (%d tools)", skill_id, len(tools))
        except Exception as e:
            logger.warning("Failed to load custom skill from %s: %s", f, e)


def get_all_custom_tools() -> list[dict]:
    """Get all tools from all installed custom skills."""
    all_tools = []
    for tools in CUSTOM_SKILL_TOOLS.values():
        all_tools.extend(tools)
    return all_tools
