# Familiar - Self-Hosted AI Agent Framework
# Copyright (c) 2026 George Scott Foley
# Licensed under the MIT License - see LICENSE file for details

"""
Guidance system for workflow-driven agent interactions.

Provides configurable guidance templates that direct agent behavior
for structured tasks (intake, troubleshooting, etc.)

Also auto-generates SkillGuidance from loaded skill metadata so that
ToolRouter can score tools by intent keywords without a manual TOOLS.yaml.
"""

import logging
import re
from dataclasses import dataclass, field
from typing import Any, Dict, List, Optional

logger = logging.getLogger(__name__)

# Stop words filtered from auto-generated keywords (same set as ToolRouter)
_STOP_WORDS: frozenset = frozenset(
    {
        "the", "a", "an", "is", "to", "in", "for", "of", "and", "or",
        "my", "me", "i", "it", "its", "with", "at", "by", "from", "on",
        "be", "can", "will", "do", "what", "how", "when", "where", "which",
        "who", "please", "help", "get", "show", "make", "tell", "give",
        "list", "that", "this", "are", "was", "were", "has", "have", "had",
        "some", "all", "any", "just", "not", "but", "so", "if", "then",
        "than", "up", "out", "about", "into", "after", "before", "over",
    }
)


@dataclass
class GuidanceConfig:
    """Configuration for the guidance system."""

    template_dir: str = "guidance_templates"
    default_template: str = "general"
    max_steps: int = 20
    allow_dynamic: bool = True


@dataclass
class ChainSpec:
    """A chain-with target: after this tool, suggest another."""

    tool: str
    condition: str = ""


@dataclass
class ToolGuidance:
    """Guidance metadata for a single tool."""

    parsed_chains: List[ChainSpec] = field(default_factory=list)
    example_prompts: List[str] = field(default_factory=list)


@dataclass
class IntentPattern:
    """Keyword pattern that maps to a tool suggestion."""

    keywords: List[str] = field(default_factory=list)
    suggest: str = ""


@dataclass
class SkillGuidance:
    """Guidance metadata for a skill (group of tools)."""

    priority: int = 5
    tools: Dict[str, ToolGuidance] = field(default_factory=dict)
    intent_patterns: List[IntentPattern] = field(default_factory=list)


class GuidanceLoader:
    """Loads and manages guidance templates for structured workflows.

    Also provides ``skill_guidance`` — a dict of SkillGuidance objects
    consumed by ToolRouter for intent-based tool scoring.  Populated
    either from TOOLS.yaml files or auto-generated from skill metadata
    via ``generate_from_skills()``.
    """

    def __init__(self, config: Optional[GuidanceConfig] = None):
        self.config = config or GuidanceConfig()
        self._templates: Dict[str, Any] = {}
        self.skill_guidance: Dict[str, SkillGuidance] = {}
        logger.debug(f"GuidanceLoader initialized with config: {self.config}")

    def load_template(self, name: str) -> Optional[Dict]:
        """Load a guidance template by name."""
        return self._templates.get(name)

    def register_template(self, name: str, template: Dict) -> None:
        """Register a guidance template."""
        self._templates[name] = template

    def list_templates(self) -> List[str]:
        """List available template names."""
        return list(self._templates.keys())

    def generate_from_skills(self, skills: dict) -> None:
        """Auto-generate skill_guidance from loaded Skill objects.

        Args:
            skills: Dict[str, Skill] — the SkillLoader.skills dict.
        """
        self.skill_guidance.clear()

        for skill_name, skill in skills.items():
            if not getattr(skill, "enabled", True):
                continue

            sg = SkillGuidance(priority=5)

            for tool in getattr(skill, "tools", []):
                tool_name = tool.name

                # Build ToolGuidance
                tg = ToolGuidance()

                # Extract example_prompts from tool.input_examples if available
                input_examples = getattr(tool, "input_examples", None)
                if input_examples:
                    for ex in input_examples:
                        if isinstance(ex, dict):
                            # Use the first string value as a prompt hint
                            for v in ex.values():
                                if isinstance(v, str) and len(v) > 3:
                                    tg.example_prompts.append(v)
                                    break

                sg.tools[tool_name] = tg

                # Build IntentPattern from tool name + description keywords
                raw_tokens = set(re.findall(r"\w+", tool_name.replace("_", " ").lower()))
                desc = getattr(tool, "description", "") or ""
                raw_tokens.update(re.findall(r"\w+", desc.lower()))
                keywords = [w for w in raw_tokens if w not in _STOP_WORDS and len(w) > 1]
                keywords = keywords[:10]  # Cap at 10 to avoid noise

                if keywords:
                    sg.intent_patterns.append(
                        IntentPattern(keywords=keywords, suggest=tool_name)
                    )

            if sg.tools:
                self.skill_guidance[skill_name] = sg

        logger.debug(
            f"GuidanceLoader: generated guidance for {len(self.skill_guidance)} skills"
        )
