"""
Constants and mappings for NotebookLM API.

This module acts as the Single Source of Truth for all API constants, code mappings,
and validation logic. It decouples data definitions from the client logic and
presentation layer.
"""

from typing import TypeVar

T = TypeVar("T")


class CodeMapper:
    """
    Bidirectional mapping for API codes.

    Handles strict validation, normalization (case-insensitivity), and
    human-readable error messages.
    """

    def __init__(self, mapping: dict[str, int], unknown_label: str = "unknown"):
        # Store as lower-case keys for case-insensitive lookup
        self._name_to_code: dict[str, int] = {k.lower(): v for k, v in mapping.items()}
        # Reverse mapping for code -> name lookup
        self._code_to_name: dict[int, str] = {v: k for k, v in mapping.items()}
        self._unknown_label = unknown_label
        # Keep original display names (keys) sorted for error messages
        self._display_names = sorted(list(mapping.keys()))

    def get_code(self, name: str) -> int:
        """
        Get integer code for a string name.

        Args:
            name: The string name (case-insensitive).

        Returns:
            The corresponding integer code.

        Raises:
            ValueError: If the name is unknown.
        """
        if not name:
            raise ValueError(f"Invalid name: '{name}'. Must be one of: {self.options_str}")

        code = self._name_to_code.get(name.lower())
        if code is None:
            raise ValueError(f"Unknown name '{name}'. Must be one of: {self.options_str}")
        return code

    def get_name(self, code: int | None) -> str:
        """
        Get string name for an integer code.

        Args:
            code: The integer code.

        Returns:
            The corresponding string name, or the 'unknown_label' if not found.
        """
        if code is None:
            return self._unknown_label
        return self._code_to_name.get(code, self._unknown_label)

    @property
    def options_str(self) -> str:
        """Return comma-separated list of valid options."""
        return ", ".join(self._display_names)

    @property
    def names(self) -> list[str]:
        """Return list of valid option names."""
        return self._display_names


# =============================================================================
# Ownership Constants
# =============================================================================
OWNERSHIP_MINE = 1
OWNERSHIP_SHARED = 2

# =============================================================================
# Chat Configuration
# =============================================================================
CHAT_GOAL_DEFAULT = 1
CHAT_GOAL_CUSTOM = 2
CHAT_GOAL_LEARNING_GUIDE = 3

CHAT_GOALS = CodeMapper(
    {
        "default": CHAT_GOAL_DEFAULT,
        "custom": CHAT_GOAL_CUSTOM,
        "learning_guide": CHAT_GOAL_LEARNING_GUIDE,
    }
)

CHAT_RESPONSE_DEFAULT = 1
CHAT_RESPONSE_LONGER = 4
CHAT_RESPONSE_SHORTER = 5

CHAT_RESPONSE_LENGTHS = CodeMapper(
    {
        "default": CHAT_RESPONSE_DEFAULT,
        "longer": CHAT_RESPONSE_LONGER,
        "shorter": CHAT_RESPONSE_SHORTER,
    }
)

# =============================================================================
# Research / Source Discovery
# =============================================================================
RESEARCH_SOURCE_WEB = 1
RESEARCH_SOURCE_DRIVE = 2

RESEARCH_SOURCES = CodeMapper(
    {
        "web": RESEARCH_SOURCE_WEB,
        "drive": RESEARCH_SOURCE_DRIVE,
    }
)

RESEARCH_MODE_FAST = 1
RESEARCH_MODE_DEEP = 5

RESEARCH_MODES = CodeMapper(
    {
        "fast": RESEARCH_MODE_FAST,
        "deep": RESEARCH_MODE_DEEP,
    }
)

RESULT_TYPE_WEB = 1
RESULT_TYPE_GOOGLE_DOC = 2
RESULT_TYPE_GOOGLE_SLIDES = 3
RESULT_TYPE_DEEP_REPORT = 5
RESULT_TYPE_GOOGLE_SHEETS = 8

RESULT_TYPES = CodeMapper(
    {
        "web": RESULT_TYPE_WEB,
        "google_doc": RESULT_TYPE_GOOGLE_DOC,
        "google_slides": RESULT_TYPE_GOOGLE_SLIDES,
        "deep_report": RESULT_TYPE_DEEP_REPORT,
        "google_sheets": RESULT_TYPE_GOOGLE_SHEETS,
    }
)

# =============================================================================
# Source Types (Notebook Content)
# =============================================================================
SOURCE_TYPE_GOOGLE_DOCS = 1
SOURCE_TYPE_GOOGLE_OTHER = 2
SOURCE_TYPE_PDF = 3
SOURCE_TYPE_PASTED_TEXT = 4
SOURCE_TYPE_WEB_PAGE = 5
SOURCE_TYPE_GENERATED_TEXT = 8
SOURCE_TYPE_YOUTUBE = 9
SOURCE_TYPE_AUDIO = 10
SOURCE_TYPE_UPLOADED_FILE = 11
SOURCE_TYPE_IMAGE = 13
SOURCE_TYPE_WORD_DOC = 14

SOURCE_TYPES = CodeMapper(
    {
        "google_docs": SOURCE_TYPE_GOOGLE_DOCS,
        "google_slides_sheets": SOURCE_TYPE_GOOGLE_OTHER,
        "pdf": SOURCE_TYPE_PDF,
        "pasted_text": SOURCE_TYPE_PASTED_TEXT,
        "web_page": SOURCE_TYPE_WEB_PAGE,
        "generated_text": SOURCE_TYPE_GENERATED_TEXT,
        "youtube": SOURCE_TYPE_YOUTUBE,
        "audio": SOURCE_TYPE_AUDIO,
        "uploaded_file": SOURCE_TYPE_UPLOADED_FILE,
        "image": SOURCE_TYPE_IMAGE,
        "word_doc": SOURCE_TYPE_WORD_DOC,
    }
)

# =============================================================================
# Studio Types
# =============================================================================
STUDIO_TYPE_AUDIO = 1
STUDIO_TYPE_REPORT = 2
STUDIO_TYPE_VIDEO = 3
STUDIO_TYPE_FLASHCARDS = 4  # Also Quiz
STUDIO_TYPE_INFOGRAPHIC = 7
STUDIO_TYPE_SLIDE_DECK = 8
STUDIO_TYPE_DATA_TABLE = 9

STUDIO_TYPES = CodeMapper(
    {
        "audio": STUDIO_TYPE_AUDIO,
        "report": STUDIO_TYPE_REPORT,
        "video": STUDIO_TYPE_VIDEO,
        "flashcards": STUDIO_TYPE_FLASHCARDS,
        "infographic": STUDIO_TYPE_INFOGRAPHIC,
        "slide_deck": STUDIO_TYPE_SLIDE_DECK,
        "data_table": STUDIO_TYPE_DATA_TABLE,
    }
)

# Index in the artifact data array where custom prompt/options are stored
STUDIO_ARTIFACT_FOCUS_INDEX = 6

# =============================================================================
# Audio Overview
# =============================================================================
AUDIO_FORMAT_DEEP_DIVE = 1
AUDIO_FORMAT_BRIEF = 2
AUDIO_FORMAT_CRITIQUE = 3
AUDIO_FORMAT_DEBATE = 4

AUDIO_FORMATS = CodeMapper(
    {
        "deep_dive": AUDIO_FORMAT_DEEP_DIVE,
        "brief": AUDIO_FORMAT_BRIEF,
        "critique": AUDIO_FORMAT_CRITIQUE,
        "debate": AUDIO_FORMAT_DEBATE,
    }
)

AUDIO_LENGTH_SHORT = 1
AUDIO_LENGTH_DEFAULT = 2
AUDIO_LENGTH_LONG = 3

AUDIO_LENGTHS = CodeMapper(
    {
        "short": AUDIO_LENGTH_SHORT,
        "default": AUDIO_LENGTH_DEFAULT,
        "long": AUDIO_LENGTH_LONG,
    }
)

# =============================================================================
# Video Overview
# =============================================================================
VIDEO_FORMAT_EXPLAINER = 1
VIDEO_FORMAT_BRIEF = 2
VIDEO_FORMAT_CINEMATIC = 3

VIDEO_FORMATS = CodeMapper(
    {
        "explainer": VIDEO_FORMAT_EXPLAINER,
        "brief": VIDEO_FORMAT_BRIEF,
        "cinematic": VIDEO_FORMAT_CINEMATIC,
    }
)

VIDEO_STYLE_AUTO_SELECT = 1
VIDEO_STYLE_CUSTOM = 2
VIDEO_STYLE_CLASSIC = 3
VIDEO_STYLE_WHITEBOARD = 4
VIDEO_STYLE_KAWAII = 5
VIDEO_STYLE_ANIME = 6
VIDEO_STYLE_WATERCOLOR = 7
VIDEO_STYLE_RETRO_PRINT = 8
VIDEO_STYLE_HERITAGE = 9
VIDEO_STYLE_PAPER_CRAFT = 10

VIDEO_STYLES = CodeMapper(
    {
        "auto_select": VIDEO_STYLE_AUTO_SELECT,
        "custom": VIDEO_STYLE_CUSTOM,
        "classic": VIDEO_STYLE_CLASSIC,
        "whiteboard": VIDEO_STYLE_WHITEBOARD,
        "kawaii": VIDEO_STYLE_KAWAII,
        "anime": VIDEO_STYLE_ANIME,
        "watercolor": VIDEO_STYLE_WATERCOLOR,
        "retro_print": VIDEO_STYLE_RETRO_PRINT,
        "heritage": VIDEO_STYLE_HERITAGE,
        "paper_craft": VIDEO_STYLE_PAPER_CRAFT,
    }
)

# =============================================================================
# Infographic
# =============================================================================
INFOGRAPHIC_ORIENTATION_LANDSCAPE = 1
INFOGRAPHIC_ORIENTATION_PORTRAIT = 2
INFOGRAPHIC_ORIENTATION_SQUARE = 3

INFOGRAPHIC_ORIENTATIONS = CodeMapper(
    {
        "landscape": INFOGRAPHIC_ORIENTATION_LANDSCAPE,
        "portrait": INFOGRAPHIC_ORIENTATION_PORTRAIT,
        "square": INFOGRAPHIC_ORIENTATION_SQUARE,
    }
)

INFOGRAPHIC_DETAIL_CONCISE = 1
INFOGRAPHIC_DETAIL_STANDARD = 2
INFOGRAPHIC_DETAIL_DETAILED = 3

INFOGRAPHIC_DETAILS = CodeMapper(
    {
        "concise": INFOGRAPHIC_DETAIL_CONCISE,
        "standard": INFOGRAPHIC_DETAIL_STANDARD,
        "detailed": INFOGRAPHIC_DETAIL_DETAILED,
    }
)

INFOGRAPHIC_STYLE_AUTO_SELECT = 1
INFOGRAPHIC_STYLE_SKETCH_NOTE = 2
INFOGRAPHIC_STYLE_PROFESSIONAL = 3
INFOGRAPHIC_STYLE_BENTO_GRID = 4
INFOGRAPHIC_STYLE_EDITORIAL = 5
INFOGRAPHIC_STYLE_INSTRUCTIONAL = 6
INFOGRAPHIC_STYLE_BRICKS = 7
INFOGRAPHIC_STYLE_CLAY = 8
INFOGRAPHIC_STYLE_ANIME = 9
INFOGRAPHIC_STYLE_KAWAII = 10
INFOGRAPHIC_STYLE_SCIENTIFIC = 11

INFOGRAPHIC_STYLES = CodeMapper(
    {
        "auto_select": INFOGRAPHIC_STYLE_AUTO_SELECT,
        "sketch_note": INFOGRAPHIC_STYLE_SKETCH_NOTE,
        "professional": INFOGRAPHIC_STYLE_PROFESSIONAL,
        "bento_grid": INFOGRAPHIC_STYLE_BENTO_GRID,
        "editorial": INFOGRAPHIC_STYLE_EDITORIAL,
        "instructional": INFOGRAPHIC_STYLE_INSTRUCTIONAL,
        "bricks": INFOGRAPHIC_STYLE_BRICKS,
        "clay": INFOGRAPHIC_STYLE_CLAY,
        "anime": INFOGRAPHIC_STYLE_ANIME,
        "kawaii": INFOGRAPHIC_STYLE_KAWAII,
        "scientific": INFOGRAPHIC_STYLE_SCIENTIFIC,
    }
)

# =============================================================================
# Slide Deck
# =============================================================================
SLIDE_DECK_FORMAT_DETAILED = 1
SLIDE_DECK_FORMAT_PRESENTER = 2

SLIDE_DECK_FORMATS = CodeMapper(
    {
        "detailed_deck": SLIDE_DECK_FORMAT_DETAILED,
        "presenter_slides": SLIDE_DECK_FORMAT_PRESENTER,
    }
)

SLIDE_DECK_LENGTH_SHORT = 1
SLIDE_DECK_LENGTH_DEFAULT = 3

SLIDE_DECK_LENGTHS = CodeMapper(
    {
        "short": SLIDE_DECK_LENGTH_SHORT,
        "default": SLIDE_DECK_LENGTH_DEFAULT,
    }
)

# =============================================================================
# Flashcards / Quiz
# =============================================================================
FLASHCARD_DIFFICULTY_EASY = 1
FLASHCARD_DIFFICULTY_MEDIUM = 2
FLASHCARD_DIFFICULTY_HARD = 3

FLASHCARD_DIFFICULTIES = CodeMapper(
    {
        "easy": FLASHCARD_DIFFICULTY_EASY,
        "medium": FLASHCARD_DIFFICULTY_MEDIUM,
        "hard": FLASHCARD_DIFFICULTY_HARD,
    }
)

FLASHCARD_COUNT_DEFAULT = 2

# =============================================================================
# Reports
# =============================================================================
REPORT_FORMAT_BRIEFING_DOC = "Briefing Doc"
REPORT_FORMAT_STUDY_GUIDE = "Study Guide"
REPORT_FORMAT_BLOG_POST = "Blog Post"
REPORT_FORMAT_CUSTOM = "Create Your Own"

# =============================================================================
# Sharing / Access Control
# =============================================================================
SHARE_ROLE_OWNER = 1
SHARE_ROLE_EDITOR = 2
SHARE_ROLE_VIEWER = 3

SHARE_ROLES = CodeMapper(
    {
        "owner": SHARE_ROLE_OWNER,
        "editor": SHARE_ROLE_EDITOR,
        "viewer": SHARE_ROLE_VIEWER,
    }
)

SHARE_ACCESS_RESTRICTED = 0
SHARE_ACCESS_PUBLIC = 1

SHARE_ACCESS_LEVELS = CodeMapper(
    {
        "restricted": SHARE_ACCESS_RESTRICTED,
        "public": SHARE_ACCESS_PUBLIC,
    }
)

# =============================================================================
# Export Types (Google Workspace)
# =============================================================================
EXPORT_TYPE_DOCS = 1
EXPORT_TYPE_SHEETS = 2

EXPORT_TYPES = CodeMapper(
    {
        "docs": EXPORT_TYPE_DOCS,
        "sheets": EXPORT_TYPE_SHEETS,
    }
)
