"""AI context generation for machine-readable project maps.

Generates .prisme/ai-context.json alongside the manifest to give AI
assistants structured metadata about the project: extension points,
generated-readonly directories, spec paths, and common commands.
"""

from __future__ import annotations

import json
from dataclasses import dataclass, field
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from pathlib import Path

    from prisme.config.loader import PrismeConfig
    from prisme.spec.project import ProjectSpec
    from prisme.tracking.manifest import FileManifest


@dataclass
class AIContext:
    """Machine-readable project context for AI assistants."""

    spec_path: str
    project_name: str
    prisme_version: str
    models: list[str] = field(default_factory=list)
    generated_readonly_dirs: list[str] = field(default_factory=list)
    extension_points: list[dict[str, str]] = field(default_factory=list)
    commands: dict[str, str] = field(default_factory=dict)
    protected_region_marker: str = "PRISM:PROTECTED"
    file_strategies: dict[str, str] = field(default_factory=dict)

    def to_dict(self) -> dict:
        """Convert to dictionary for JSON serialization."""
        return {
            "spec_path": self.spec_path,
            "project_name": self.project_name,
            "prisme_version": self.prisme_version,
            "models": self.models,
            "generated_readonly_dirs": self.generated_readonly_dirs,
            "extension_points": self.extension_points,
            "commands": self.commands,
            "protected_region_marker": self.protected_region_marker,
            "file_strategies": self.file_strategies,
        }


class AIContextManager:
    """Manager for generating and saving AI context files."""

    CONTEXT_FILE = "ai-context.json"
    CONTEXT_DIR = ".prisme"

    @staticmethod
    def generate(
        output_dir: Path,
        spec_file: Path,
        project_name: str,
        model_names: list[str],
        manifest: FileManifest,
        prisme_config: PrismeConfig | None = None,
        project_spec: ProjectSpec | None = None,
    ) -> None:
        """Generate and save ai-context.json alongside the manifest.

        Args:
            output_dir: The project root directory.
            spec_file: Path to the spec file.
            project_name: Name of the project.
            model_names: List of model names from the spec.
            manifest: The file manifest with tracked files.
            prisme_config: Optional prisme.toml config.
            project_spec: Optional project spec.
        """
        try:
            from prisme import __version__

            version = __version__
        except Exception as e:
            import logging

            logging.getLogger("prisme").debug("Version detection failed: %s", e)
            version = "unknown"

        # Build generated-readonly dirs from manifest
        readonly_dirs: set[str] = set()
        extension_points: list[dict[str, str]] = []
        file_strategies: dict[str, str] = {}

        for path_str, tracked in manifest.files.items():
            file_strategies[path_str] = tracked.strategy

            # Identify generated-readonly directories
            if tracked.strategy == "always_overwrite":
                parts = path_str.split("/")
                for i, part in enumerate(parts):
                    if part in ("_generated", "schemas", "types"):
                        readonly_dirs.add("/".join(parts[: i + 1]))

            # Identify extension points
            if tracked.extends:
                extension_points.append(
                    {
                        "path": path_str,
                        "base": tracked.extends,
                        "strategy": tracked.strategy,
                    }
                )

        context = AIContext(
            spec_path=str(spec_file),
            project_name=project_name,
            prisme_version=version,
            models=model_names,
            generated_readonly_dirs=sorted(readonly_dirs),
            extension_points=extension_points,
            commands={
                "validate": f"uv run prism validate {spec_file}",
                "generate": "uv run prism generate",
                "generate_preview": "uv run prism generate --dry-run",
                "migrate": "uv run prism db migrate",
                "test": "uv run prism test",
                "dev": "uv run prism dev",
                "check": "uv run prism check",
                "review": "uv run prism review list",
            },
            protected_region_marker="PRISM:PROTECTED",
            file_strategies=file_strategies,
        )

        AIContextManager.save(context, output_dir)

    @staticmethod
    def save(context: AIContext, project_dir: Path) -> None:
        """Save the AI context to disk.

        Args:
            context: The AIContext to save.
            project_dir: The project root directory.
        """
        context_path = project_dir / AIContextManager.CONTEXT_DIR / AIContextManager.CONTEXT_FILE
        context_path.parent.mkdir(parents=True, exist_ok=True)

        with context_path.open("w") as f:
            json.dump(context.to_dict(), f, indent=2)

    @staticmethod
    def load(project_dir: Path) -> AIContext | None:
        """Load the AI context from disk.

        Args:
            project_dir: The project root directory.

        Returns:
            The AIContext if found, None otherwise.
        """
        context_path = project_dir / AIContextManager.CONTEXT_DIR / AIContextManager.CONTEXT_FILE

        if not context_path.exists():
            return None

        try:
            with context_path.open("r") as f:
                data = json.load(f)
            return AIContext(**data)
        except (OSError, json.JSONDecodeError, TypeError):
            return None


__all__ = [
    "AIContext",
    "AIContextManager",
]
