"""
Local Prompt Loader

Load prompts from local files that were pulled using the CLI.
Supports both JSON and TXT formats.

Example:
    >>> from promptcanvas import LocalPrompts
    >>> 
    >>> prompts = LocalPrompts(dir="./prompts")
    >>> 
    >>> # Load a prompt
    >>> prompt = prompts.get("system-prompt")
    >>> print(prompt.content)
    >>> 
    >>> # Load with variables
    >>> prompt = prompts.get("welcome", variables={"name": "John"})
"""

import json
from pathlib import Path
from typing import Dict, List, Optional, Union

from .errors import PromptNotFoundError
from .models import Prompt
from .variables import VariableResolver

VariableValue = Union[str, int, float, bool]


class LocalPrompts:
    """
    Load prompts from local files.
    
    Args:
        dir: Directory containing prompt files (default: "prompts")
        
    Example:
        >>> prompts = LocalPrompts()
        >>> prompt = prompts.get("system-prompt")
        >>> print(prompt.content)
    """

    def __init__(self, dir: str = "prompts") -> None:
        self._dir = Path.cwd() / dir
        self._cache: Dict[str, Prompt] = {}

        if not self._dir.exists():
            raise FileNotFoundError(
                f"Prompts directory not found: {self._dir}\n"
                "Run 'promptcanvas pull --all' to download prompts first."
            )

        # Pre-load all prompts
        self._load_all()

    def get(
        self,
        slug: str,
        variables: Optional[Dict[str, VariableValue]] = None,
    ) -> Prompt:
        """
        Get a prompt by slug.
        
        Args:
            slug: The prompt slug
            variables: Optional variables to interpolate
            
        Returns:
            Prompt with variables resolved
            
        Raises:
            PromptNotFoundError: If prompt file doesn't exist
        """
        if slug in self._cache:
            prompt = self._cache[slug]
        else:
            prompt = self._load_prompt(slug)
            if prompt is None:
                raise PromptNotFoundError(slug)
            self._cache[slug] = prompt

        if variables:
            resolved_content = VariableResolver.resolve(prompt.content, variables)
            return Prompt(
                slug=prompt.slug,
                name=prompt.name,
                content=resolved_content,
                version=prompt.version,
                stage=prompt.stage,
                variables=prompt.variables,
                category=prompt.category,
                tags=prompt.tags,
                updated_at=prompt.updated_at,
                etag=prompt.etag,
            )

        return prompt

    def has(self, slug: str) -> bool:
        """Check if a prompt exists locally."""
        if slug in self._cache:
            return True
        
        json_path = self._dir / f"{slug}.json"
        txt_path = self._dir / f"{slug}.txt"
        
        return json_path.exists() or txt_path.exists()

    def slugs(self) -> List[str]:
        """Get all loaded prompt slugs."""
        return list(self._cache.keys())

    def all(self) -> List[Prompt]:
        """Get all loaded prompts."""
        return list(self._cache.values())

    def reload(self) -> None:
        """Reload all prompts from disk."""
        self._cache.clear()
        self._load_all()

    def _load_all(self) -> None:
        """Load all prompts from the directory."""
        if not self._dir.exists():
            return

        for file in self._dir.iterdir():
            if file.suffix in (".json", ".txt"):
                slug = file.stem
                prompt = self._load_prompt(slug)
                if prompt:
                    self._cache[slug] = prompt

    def _load_prompt(self, slug: str) -> Optional[Prompt]:
        """Load a single prompt file."""
        # Try JSON first
        json_path = self._dir / f"{slug}.json"
        if json_path.exists():
            try:
                with open(json_path, "r") as f:
                    data = json.load(f)
                return self._normalize_prompt(slug, data)
            except Exception:
                return None

        # Try TXT
        txt_path = self._dir / f"{slug}.txt"
        if txt_path.exists():
            content = txt_path.read_text()
            return Prompt(
                slug=slug,
                name=slug,
                content=content,
                version=0,
                stage="production",
                variables=VariableResolver.extract(content),
                category="",
                tags=[],
                updated_at="",
                etag="",
            )

        return None

    def _normalize_prompt(self, slug: str, data: Dict) -> Prompt:
        """Normalize prompt data from JSON file."""
        return Prompt(
            slug=data.get("slug", slug),
            name=data.get("name", slug),
            content=data.get("content", ""),
            version=data.get("version", 0),
            stage="production",
            variables=data.get("variables", VariableResolver.extract(data.get("content", ""))),
            category=data.get("category", ""),
            tags=data.get("tags", []),
            updated_at=data.get("updatedAt", data.get("updated_at", "")),
            etag=data.get("etag", ""),
        )


def create_local_getter(
    dir: str = "prompts",
) -> callable:
    """
    Create a simple prompt getter function.
    
    Args:
        dir: Directory containing prompt files
        
    Returns:
        A function that gets prompt content by slug
        
    Example:
        >>> from promptcanvas import create_local_getter
        >>> 
        >>> get_prompt = create_local_getter("./prompts")
        >>> 
        >>> content = get_prompt("system-prompt")
        >>> with_vars = get_prompt("welcome", name="John")
    """
    prompts = LocalPrompts(dir=dir)

    def getter(slug: str, **variables: VariableValue) -> str:
        return prompts.get(slug, variables=variables if variables else None).content

    return getter
