"""Service for managing worktree color metadata."""

from __future__ import annotations

import json
from datetime import datetime
from pathlib import Path


class ColorMetadataService:
    """Service for managing worktree color metadata."""

    def __init__(self) -> None:
        self.metadata_dir = Path.home() / ".portal" / "metadata" / "projects"

    async def save_worktree_color(
        self, project_name: str, worktree_name: str, color_name: str
    ) -> None:
        """Save color assignment for a worktree."""
        self._validate_names(project_name, worktree_name, color_name)

        project_file = self._get_project_file(project_name)
        data = self._load_project_data(project_file)

        now = datetime.now().isoformat()
        data["worktrees"][worktree_name] = {
            "color": color_name,
            "assigned_at": now,
            "last_accessed": now,
        }

        self._save_project_data(project_file, data)

    async def get_worktree_color(self, project_name: str, worktree_name: str) -> str | None:
        """Get saved color for a worktree."""
        self._validate_names(project_name, worktree_name)

        project_file = self._get_project_file(project_name)
        if not project_file.exists():
            return None

        data = self._load_project_data(project_file)
        worktree_data = data.get("worktrees", {}).get(worktree_name)

        if worktree_data:
            worktree_data["last_accessed"] = datetime.now().isoformat()
            self._save_project_data(project_file, data)
            return worktree_data.get("color")

        return None

    async def get_used_colors(self, project_name: str) -> set[str]:
        """Get all colors currently in use for a project."""
        self._validate_names(project_name)

        project_file = self._get_project_file(project_name)
        if not project_file.exists():
            return set()

        data = self._load_project_data(project_file)
        return {
            worktree_data["color"]
            for worktree_data in data.get("worktrees", {}).values()
            if "color" in worktree_data
        }

    async def remove_worktree_color(self, project_name: str, worktree_name: str) -> None:
        """Remove color assignment for a deleted worktree."""
        self._validate_names(project_name, worktree_name)

        project_file = self._get_project_file(project_name)
        if not project_file.exists():
            return

        data = self._load_project_data(project_file)
        if worktree_name in data.get("worktrees", {}):
            del data["worktrees"][worktree_name]
            self._save_project_data(project_file, data)

    async def list_project_worktrees(self, project_name: str) -> dict[str, dict[str, str]]:
        """List all worktrees and their colors for a project."""
        self._validate_names(project_name)

        project_file = self._get_project_file(project_name)
        if not project_file.exists():
            return {}

        data = self._load_project_data(project_file)
        return data.get("worktrees", {})

    def _validate_names(
        self, project_name: str, worktree_name: str | None = None, color_name: str | None = None
    ) -> None:
        """Validate input names to prevent path traversal and injection."""
        if (
            not project_name
            or not project_name.strip()
            or ".." in project_name
            or "/" in project_name
        ):
            raise ValueError("Invalid project name")

        if worktree_name is not None and (not worktree_name or not worktree_name.strip()):
            raise ValueError("Invalid worktree name")

        if color_name is not None and (not color_name or not color_name.strip()):
            raise ValueError("Invalid color name")

    def _get_project_file(self, project_name: str) -> Path:
        """Get the project file path safely."""
        return self.metadata_dir / project_name / "worktrees.json"

    def _load_project_data(self, project_file: Path) -> dict[str, dict[str, dict[str, str]]]:
        """Load project data safely with error handling."""
        try:
            if project_file.exists():
                with open(project_file, encoding="utf-8") as f:
                    data = json.load(f)
                    return data  # type: ignore[no-any-return]
            return {"worktrees": {}}
        except (json.JSONDecodeError, OSError):
            # If file is corrupted or can't be read, start fresh
            return {"worktrees": {}}

    def _save_project_data(
        self, project_file: Path, data: dict[str, dict[str, dict[str, str]]]
    ) -> None:
        """Save project data safely with error handling."""
        try:
            project_file.parent.mkdir(parents=True, exist_ok=True)
            with open(project_file, "w", encoding="utf-8") as f:
                json.dump(data, f, indent=2, ensure_ascii=False)
        except OSError as e:
            raise RuntimeError(f"Failed to save color metadata: {e}") from e
