"""Cache management for NanoWiki."""

from __future__ import annotations

import json
from datetime import datetime
from pathlib import Path
from typing import Any

from .models import WikiPage


class WikiCache:
    """Simple cache structure for wiki data."""

    def __init__(
        self,
        project_path: str,
        pages: list[WikiPage],
        created_at: datetime | None = None,
        updated_at: datetime | None = None,
    ):
        self.project_path = project_path
        self.pages = pages
        self.created_at = created_at or datetime.now()
        self.updated_at = updated_at or datetime.now()

    def to_dict(self) -> dict[str, Any]:
        """Convert to dictionary for JSON serialization."""
        return {
            "project_path": self.project_path,
            "pages": [
                {
                    "title": p.title,
                    "content": p.content,
                    "path": p.path,
                    "created_at": p.created_at.isoformat(),
                    "updated_at": p.updated_at.isoformat(),
                }
                for p in self.pages
            ],
            "created_at": self.created_at.isoformat(),
            "updated_at": self.updated_at.isoformat(),
        }

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> WikiCache:
        """Create from dictionary."""
        pages = [
            WikiPage(
                title=p["title"],
                content=p["content"],
                path=p["path"],
                created_at=datetime.fromisoformat(p["created_at"]),
                updated_at=datetime.fromisoformat(p["updated_at"]),
            )
            for p in data.get("pages", [])
        ]
        return cls(
            project_path=data["project_path"],
            pages=pages,
            created_at=(
                datetime.fromisoformat(data["created_at"])
                if data.get("created_at") else None
            ),
            updated_at=(
                datetime.fromisoformat(data["updated_at"])
                if data.get("updated_at") else None
            ),
        )


class WikiCacheManager:
    """Manage wiki cache storage."""

    CACHE_FILENAME = "cache.json"
    DEFAULT_WIKI_DIR = ".wiki"

    def __init__(self, project_path: Path, wiki_dir: Path | None = None):
        """Initialize cache manager.

        Args:
            project_path: Path to the project being analyzed
            wiki_dir: Custom wiki directory (default: project_path/.wiki)
        """
        self.project_path = project_path.resolve()
        self.wiki_dir = (wiki_dir or (project_path / self.DEFAULT_WIKI_DIR)).resolve()
        self.cache_file = self.wiki_dir / self.CACHE_FILENAME

    def is_cached(self) -> bool:
        """Check if wiki cache exists and is valid.

        Returns:
            True if cache exists
        """
        return self.cache_file.exists()

    def load_cache(self) -> WikiCache | None:
        """Load wiki cache from disk.

        Returns:
            WikiCache if cache exists and is valid, None otherwise
        """
        if not self.is_cached():
            return None

        try:
            data = json.loads(self.cache_file.read_text(encoding="utf-8"))
            return WikiCache.from_dict(data)
        except Exception as e:
            print(f"Warning: Failed to load cache: {e}")
            return None

    def save_cache(self, cache: WikiCache) -> None:
        """Save wiki cache to disk.

        Args:
            cache: WikiCache to save
        """
        # Ensure wiki directory exists
        self.wiki_dir.mkdir(parents=True, exist_ok=True)

        # Save cache
        self.cache_file.write_text(
            json.dumps(cache.to_dict(), indent=2, ensure_ascii=False),
            encoding="utf-8",
        )

    def save_pages(self, pages: list[WikiPage]) -> None:
        """Save pages to cache and disk.

        Args:
            pages: Generated wiki pages
        """
        cache = WikiCache(
            project_path=str(self.project_path),
            pages=pages,
        )
        self.save_cache(cache)
        self.write_pages(pages)

    def load_pages(self) -> list[WikiPage]:
        """Load pages from cache.

        Returns:
            List of WikiPage objects, empty list if cache doesn't exist
        """
        cache = self.load_cache()
        if cache:
            return cache.pages
        return []

    def invalidate(self) -> None:
        """Remove cache and wiki directory."""
        if self.wiki_dir.exists():
            # Remove all contents
            for item in self.wiki_dir.iterdir():
                if item.is_file():
                    item.unlink()
                elif item.is_dir():
                    for sub_item in item.rglob("*"):
                        if sub_item.is_file():
                            sub_item.unlink()
                        elif sub_item.is_dir():
                            sub_item.rmdir()
                    item.rmdir()

    def write_page(self, page: WikiPage) -> Path:
        """Write a wiki page to disk.

        Args:
            page: WikiPage to write

        Returns:
            Path to the written file
        """
        # Ensure wiki directory exists
        self.wiki_dir.mkdir(parents=True, exist_ok=True)

        # Write page
        page_path = self.wiki_dir / page.path
        page_path.parent.mkdir(parents=True, exist_ok=True)
        page_path.write_text(page.content, encoding="utf-8")

        return page_path

    def write_pages(self, pages: list[WikiPage]) -> list[Path]:
        """Write multiple wiki pages to disk.

        Args:
            pages: List of WikiPage objects to write

        Returns:
            List of paths to written files
        """
        paths = []
        for page in pages:
            path = self.write_page(page)
            paths.append(path)
        return paths

    def read_page(self, path: str) -> str | None:
        """Read a wiki page from disk.

        Args:
            path: Relative path from wiki root

        Returns:
            Page content if file exists, None otherwise
        """
        page_path = self.wiki_dir / path
        if page_path.exists() and page_path.is_file():
            return page_path.read_text(encoding="utf-8")
        return None

    def list_pages(self) -> list[Path]:
        """List all markdown files in the wiki directory.

        Returns:
            List of paths relative to wiki root
        """
        if not self.wiki_dir.exists():
            return []

        pages = []
        for md_file in self.wiki_dir.rglob("*.md"):
            pages.append(md_file.relative_to(self.wiki_dir))

        return sorted(pages)

    def get_project_name(self) -> str:
        """Get project name from project path.

        Returns:
            Project name (directory name)
        """
        return self.project_path.name
