# 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 package validation for all entity types.

Extends the validation logic from jobs/_marketplace.py to cover
species and familiar (bundle) package types.
"""

import re
from typing import Optional

SCHEMA_VERSION = "1.0"

_REQUIRED_METADATA = {"id", "name", "version"}
_VALID_TYPES = {"job_class", "skill", "bundle", "species", "familiar"}

_REQUIRED_SPECIES = {"key", "label", "description", "personality", "baby_preview"}
_REQUIRED_BUNDLE = {"name"}
_REQUIRED_JOB_CLASS = {"key", "name", "description", "prompt_fragment"}


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

    # Schema version
    sv = data.get("schema_version", "")
    if not sv:
        errors.append("Missing 'schema_version'")
    elif sv != SCHEMA_VERSION:
        errors.append(f"Unsupported schema_version '{sv}' (expected '{SCHEMA_VERSION}')")

    # Type
    pkg_type = data.get("type", "")
    if not pkg_type:
        errors.append("Missing 'type'")
    elif pkg_type not in _VALID_TYPES:
        errors.append(
            f"Invalid type '{pkg_type}' (expected one of: {', '.join(sorted(_VALID_TYPES))})"
        )

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

        version = meta.get("version", "")
        if version and not re.match(r"^\d+\.\d+\.\d+$", version):
            errors.append(f"Invalid version format '{version}' (expected X.Y.Z)")

        fv = meta.get("familiar_version", "")
        if fv:
            match = re.match(r">=(\d+\.\d+\.\d+)", fv)
            if not match:
                errors.append(f"Invalid familiar_version constraint '{fv}' (expected '>=X.Y.Z')")

    # Type-specific validation
    if pkg_type == "species":
        errors.extend(_validate_species(data))
    elif pkg_type == "familiar":
        errors.extend(_validate_bundle(data))
    elif pkg_type == "job_class":
        errors.extend(_validate_job_class(data))

    return errors


def _validate_species(data: dict) -> list[str]:
    """Validate the species section of a species package."""
    errors: list[str] = []
    sp = data.get("species", {})
    if not sp:
        errors.append("Missing 'species' section")
    else:
        for field in _REQUIRED_SPECIES:
            if not sp.get(field):
                errors.append(f"Missing species.{field}")
    return errors


def _validate_bundle(data: dict) -> list[str]:
    """Validate the bundle section of a familiar package."""
    errors: list[str] = []
    bundle = data.get("bundle", {})
    if not bundle:
        errors.append("Missing 'bundle' section")
    else:
        for field in _REQUIRED_BUNDLE:
            if not bundle.get(field):
                errors.append(f"Missing bundle.{field}")
    return errors


def _validate_job_class(data: dict) -> list[str]:
    """Validate the job_class section."""
    errors: list[str] = []
    jc = data.get("job_class", {})
    if not jc:
        errors.append("Missing 'job_class' section")
    else:
        for field in _REQUIRED_JOB_CLASS:
            if not jc.get(field):
                errors.append(f"Missing job_class.{field}")
    return errors


def check_compatibility(data: dict) -> Optional[str]:
    """Check if a package is compatible with the current Familiar version.

    Returns error message if incompatible, None if compatible.
    """
    from familiar import __version__

    meta = data.get("metadata", {})
    constraint = meta.get("familiar_version", "")
    if not constraint:
        return None

    match = re.match(r">=(\d+\.\d+\.\d+)", constraint)
    if not match:
        return None

    required = tuple(int(x) for x in re.findall(r"\d+", match.group(1)))
    current = tuple(int(x) for x in re.findall(r"\d+", __version__))

    if current < required:
        return f"Package requires familiar>={match.group(1)} but current version is {__version__}"
    return None
