"""On-disk CRUD for scene metadata."""

__author__ = "Lene Preuss <lene.preuss@gmail.com>"

import json
import re
from pathlib import Path

from stable_delusion.exceptions.project_error import ProjectError
from stable_delusion.project.models import SceneMetadata


def _scene_slug(index: int, name: str) -> str:
    clean = re.sub(r"[^a-z0-9]+", "-", name.lower().strip()).strip("-")
    return f"{index:02d}-{clean}"


class SceneRepository:
    """On-disk CRUD for scene metadata within a project."""

    def create(self, project_dir: Path, name: str, metadata: SceneMetadata) -> Path:
        """Create a new scene directory with scene.json and standard subdirs."""
        slug = _scene_slug(metadata.index, name)
        scene_dir = project_dir / "scenes" / slug
        if scene_dir.exists():
            raise ProjectError(
                f"Scene directory already exists: {scene_dir}",
                project_name=project_dir.name,
            )
        scene_dir.mkdir(parents=True)
        (scene_dir / "keyframes").mkdir()
        (scene_dir / "clips").mkdir()
        self._write(scene_dir, metadata)
        return scene_dir

    def get(self, scene_dir: Path) -> SceneMetadata:
        """Read scene.json from scene directory."""
        json_path = scene_dir / "scene.json"
        if not json_path.exists():
            raise ProjectError(f"scene.json not found in {scene_dir}")
        return SceneMetadata.from_dict(json.loads(json_path.read_text(encoding="utf-8")))

    def update(self, scene_dir: Path, metadata: SceneMetadata) -> None:
        """Write updated scene.json."""
        self._write(scene_dir, metadata)

    def list_scenes(self, project_dir: Path) -> list[tuple[Path, SceneMetadata]]:
        """List all scenes in project, sorted by scene index."""
        scenes_dir = project_dir / "scenes"
        if not scenes_dir.exists():
            return []
        results = []
        for entry in scenes_dir.iterdir():
            if entry.is_dir() and (entry / "scene.json").exists():
                results.append((entry, self.get(entry)))
        return sorted(results, key=lambda x: x[1].index)

    def next_index(self, project_dir: Path) -> int:
        """Return the next available scene index (1-based)."""
        return len(self.list_scenes(project_dir)) + 1

    def _write(self, scene_dir: Path, metadata: SceneMetadata) -> None:
        json_path = scene_dir / "scene.json"
        json_path.write_text(json.dumps(metadata.to_dict(), indent=2), encoding="utf-8")
