"""File management for YAML note files."""

import logging
import re
from pathlib import Path
from typing import List, Optional

from .models import Note

logger = logging.getLogger(__name__)


class FileManager:
    """Manages reading and writing YAML note files."""

    def __init__(self, base_dir: str = "notes"):
        """Initialize file manager.

        Args:
            base_dir: Base directory for storing YAML files
        """
        self.base_dir = Path(base_dir).resolve()
        self.base_dir.mkdir(exist_ok=True, parents=True)

    def sanitize_filename(self, text: str, note_id: int) -> str:
        """Generate a safe filename from note content.

        Args:
            text: Text to use as basis for filename (typically from a field)
            note_id: Note ID for uniqueness

        Returns:
            Safe filename with .yaml extension
        """
        # Remove non-alphanumeric characters except spaces and hyphens
        safe_text = re.sub(r"[^a-zA-Z0-9\s\-]", "", text)
        # Replace spaces with hyphens
        safe_text = re.sub(r"\s+", "-", safe_text).lower()
        # Remove leading/trailing hyphens
        safe_text = safe_text.strip("-")
        # Truncate to reasonable length (leaving room for ID)
        safe_text = safe_text[:40]

        if not safe_text:
            safe_text = "note"

        # Include note ID to ensure uniqueness
        return f"{safe_text}_{note_id}.yaml"

    def _deck_to_path(self, deck: Optional[str]) -> Path:
        """Convert Anki deck name to a relative folder path.

        Args:
            deck: Anki deck name using :: nesting

        Returns:
            Relative Path representing deck nesting
        """
        if not deck:
            return Path(".")
        parts = [part for part in deck.split("::") if part]
        return Path(*parts) if parts else Path(".")

    def _path_to_deck(self, relative_path: Path) -> Optional[str]:
        """Convert a relative file path to an Anki deck name.

        Args:
            relative_path: Path relative to base_dir

        Returns:
            Deck name using :: nesting, or None if at root
        """
        parent = relative_path.parent
        if parent == Path("."):
            return None
        return "::".join(parent.parts)

    def save_note(self, note: Note) -> str:
        """Save a note to a YAML file.

        Args:
            note: The Note object to save

        Returns:
            Path to the saved file (relative to base_dir)
        """
        filename = self.sanitize_filename(note.get_summary(), note.id)
        deck_path = self._deck_to_path(note.deck)
        dirpath = self.base_dir / deck_path
        dirpath.mkdir(exist_ok=True, parents=True)
        filepath = dirpath / filename

        yaml_content = note.to_yaml()

        with open(filepath, "w", encoding="utf-8") as f:
            f.write(yaml_content)

        rel_path = filepath.relative_to(self.base_dir)
        logger.debug("Saved note %s to %s", note.id, rel_path)
        return rel_path.as_posix()

    def load_note(self, filename: str) -> Optional[Note]:
        """Load a note from a YAML file.

        Args:
            filename: Relative path to the YAML file (in base_dir)

        Returns:
            The loaded Note object, or None if file doesn't exist or is invalid
        """
        filepath = self.base_dir / filename

        if not filepath.exists():
            logger.warning("File not found: %s", filepath)
            return None

        try:
            with open(filepath, "r", encoding="utf-8") as f:
                yaml_content = f.read()

            note = Note.from_yaml(yaml_content)
            if not note.deck:
                inferred_deck = self._path_to_deck(Path(filename))
                note.deck = inferred_deck
            logger.debug("Loaded note %s from %s", note.id, filename)
            return note
        except Exception as e:  # pylint: disable=broad-exception-caught
            logger.error("Failed to load note from %s: %s", filename, e)
            return None

    def get_all_yaml_files(self) -> List[str]:
        """Get list of all YAML files in the base directory (recursive).

        Returns:
            List of YAML file paths relative to base_dir
        """
        if not self.base_dir.exists():
            return []

        yaml_files = [
            f.relative_to(self.base_dir).as_posix()
            for f in self.base_dir.rglob("*.yaml")
            if f.is_file()
        ]
        logger.debug("Found %s YAML files", len(yaml_files))
        return yaml_files

    def get_all_notes(self) -> List[Note]:
        """Load all notes from YAML files.

        Returns:
            List of loaded Note objects
        """
        yaml_files = self.get_all_yaml_files()
        notes = []

        for filename in yaml_files:
            note = self.load_note(filename)
            if note:
                notes.append(note)

        logger.debug("Loaded %s notes from %s files", len(notes), len(yaml_files))
        return notes

    def note_file_exists(self, note_id: int) -> bool:
        """Check if a YAML file exists for a note ID.

        Args:
            note_id: The note ID to check

        Returns:
            True if a file matching this note ID exists
        """
        yaml_files = self.get_all_yaml_files()
        # Check if any file contains this note ID
        return any(f"_{note_id}.yaml" in f for f in yaml_files)

    def update_note_id_in_file(self, filename: str, new_id: int) -> bool:
        """Update the ID field in a YAML file after note creation.

        Args:
            filename: The YAML file path relative to base_dir
            new_id: The new note ID to set

        Returns:
            True if successful, False otherwise
        """
        filepath = self.base_dir / filename

        if not filepath.exists():
            logger.warning("File not found: %s", filepath)
            return False

        try:
            note = self.load_note(filename)
            if not note:
                return False

            note.id = new_id
            yaml_content = note.to_yaml()

            with open(filepath, "w", encoding="utf-8") as f:
                f.write(yaml_content)

            logger.debug("Updated note ID in %s to %s", filename, new_id)
            return True
        except Exception as e:  # pylint: disable=broad-exception-caught
            logger.error("Failed to update note ID in %s: %s", filename, e)
            return False
