"""Prompt store — persistent storage for prompts with versioning."""

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

from promptkit.config import Config
from promptkit.prompt import Prompt, PromptVersion


class PromptStore:
    """Manages prompt storage on disk."""

    def __init__(self, config: Optional[Config] = None):
        self.config = config or Config()
        if not self.config.is_initialized():
            raise RuntimeError("No promptkit project found. Run 'promptkit init' first.")
        self._prompts_dir = self.config.prompts_dir
        self._cache: Dict[str, Prompt] = {}

    def _prompt_file(self, name: str) -> Path:
        """Get the file path for a prompt."""
        return self._prompts_dir / f"{name}.json"

    def _content_file(self, name: str, version: int) -> Path:
        """Get the content file path for a specific version."""
        prompt_dir = self._prompts_dir / name
        prompt_dir.mkdir(parents=True, exist_ok=True)
        return prompt_dir / f"v{version}.md"

    def save(self, prompt: Prompt) -> None:
        """Save a prompt to disk."""
        # Create prompt directory
        prompt_dir = self._prompts_dir / prompt.name
        prompt_dir.mkdir(parents=True, exist_ok=True)

        # Save metadata
        meta_file = prompt_dir / "prompt.json"
        with open(meta_file, "w") as f:
            json.dump(prompt.to_dict(), f, indent=2)

        # Save each version as separate .md file for git-friendliness
        for version in prompt.versions:
            content_file = prompt_dir / f"v{version.version}.md"
            content_file.write_text(version.content)

        # Update cache
        self._cache[prompt.name] = prompt

    def load(self, name: str) -> Optional[Prompt]:
        """Load a prompt from disk."""
        if name in self._cache:
            return self._cache[name]

        prompt_dir = self._prompts_dir / name
        meta_file = prompt_dir / "prompt.json"

        if not meta_file.exists():
            return None

        with open(meta_file, "r") as f:
            data = json.load(f)

        prompt = Prompt.from_dict(data)
        self._cache[name] = prompt
        return prompt

    def delete(self, name: str) -> bool:
        """Delete a prompt and all its versions."""
        prompt_dir = self._prompts_dir / name
        if not prompt_dir.exists():
            return False

        import shutil
        shutil.rmtree(prompt_dir)
        self._cache.pop(name, None)
        return True

    def list_prompts(self) -> List[Prompt]:
        """List all prompts."""
        prompts = []
        if not self._prompts_dir.exists():
            return prompts

        for prompt_dir in sorted(self._prompts_dir.iterdir()):
            if prompt_dir.is_dir():
                meta_file = prompt_dir / "prompt.json"
                if meta_file.exists():
                    prompt = self.load(prompt_dir.name)
                    if prompt:
                        prompts.append(prompt)
        return prompts

    def search(self, query: str) -> List[Prompt]:
        """Search prompts by name or content."""
        query = query.lower()
        results = []
        for prompt in self.list_prompts():
            if query in prompt.name.lower() or query in prompt.description.lower():
                results.append(prompt)
                continue
            # Search in latest version content
            if prompt.latest and query in prompt.latest.content.lower():
                results.append(prompt)
        return results

    def commit(
        self,
        name: str,
        content: str,
        message: str = "",
        description: str = "",
    ) -> PromptVersion:
        """Save a new version of a prompt (git-like commit)."""
        prompt = self.load(name)
        if prompt is None:
            prompt = Prompt(name=name, description=description)

        if description and not prompt.description:
            prompt.description = description

        # Check for duplicate content
        if prompt.latest and prompt.latest.content == content:
            raise ValueError("Content unchanged from latest version")

        version = prompt.add_version(content, message=message)
        self.save(prompt)
        return version

    def tag(self, name: str, tag_name: str, version: Optional[int] = None) -> None:
        """Tag a prompt version."""
        prompt = self.load(name)
        if prompt is None:
            raise ValueError(f"Prompt '{name}' not found")
        prompt.add_tag(tag_name, version)
        self.save(prompt)

    def untag(self, name: str, tag_name: str) -> bool:
        """Remove a tag from a prompt."""
        prompt = self.load(name)
        if prompt is None:
            raise ValueError(f"Prompt '{name}' not found")
        result = prompt.remove_tag(tag_name)
        if result:
            self.save(prompt)
        return result

    def get(
        self,
        name: str,
        version: Optional[int] = None,
        tag: Optional[str] = None,
        variables: Optional[Dict] = None,
    ) -> Optional[str]:
        """Get prompt content, optionally rendered with variables."""
        prompt = self.load(name)
        if prompt is None:
            return None

        ver = prompt.get_version(version=version, tag=tag)
        if ver is None:
            return None

        if variables:
            return ver.render(variables)
        return ver.content

    def diff(self, name: str, v1: int, v2: int) -> List[Dict]:
        """Get diff between two versions."""
        prompt = self.load(name)
        if prompt is None:
            raise ValueError(f"Prompt '{name}' not found")
        return prompt.diff(v1, v2)

    def export_prompt(self, name: str, output_path: Path, version: Optional[int] = None) -> None:
        """Export a prompt to a file."""
        prompt = self.load(name)
        if prompt is None:
            raise ValueError(f"Prompt '{name}' not found")

        ver = prompt.get_version(version)
        if ver is None:
            raise ValueError(f"Version not found")

        output_path.write_text(ver.content)

    def import_prompt(self, name: str, source_path: Path, message: str = "") -> PromptVersion:
        """Import a prompt from a file."""
        if not source_path.exists():
            raise FileNotFoundError(f"File not found: {source_path}")

        content = source_path.read_text()
        return self.commit(name, content, message=message or f"Imported from {source_path.name}")

    def stats(self) -> Dict:
        """Get store statistics."""
        prompts = self.list_prompts()
        total_versions = sum(p.version_count for p in prompts)
        total_tags = sum(len(p.tags) for p in prompts)
        return {
            "total_prompts": len(prompts),
            "total_versions": total_versions,
            "total_tags": total_tags,
        }
