"""Main snap() function for Skua."""

from typing import Any, Optional

from skua.client import upload_snapshot
from skua.config import get_session_public, get_web_url
from skua.result import SnapResult
from skua.serializers import serialize_object


def snap(
    obj: Any,
    title: str,
    description: Optional[str] = None,
    public: Optional[bool] = None,
    tags: Optional[list[str]] = None,
) -> SnapResult:
    """Snap and share a Python object via Skua.

    Serializes the object, uploads it to Skua, and returns a SnapResult object
    that wraps the original object while providing access to the URL and metadata.

    In Jupyter notebooks, the SnapResult displays the original object transparently,
    so you can use snap() as the last call in a cell to display the object.

    Args:
        obj: Object to snap (matplotlib figure, pandas DataFrame, etc.)
        title: Title for the snapshot (required, max 500 characters)
        description: Optional short description providing context (max 1000 characters)
        public: Override visibility for this snapshot.
                True = anyone with the URL can view.
                False = private, only you can view (requires verified account).
                None = use the default from skua.configure(public=...), or the server default
                (public for anonymous users, private for verified users).

    Returns:
        SnapResult object with:
        - Displays as the original object in notebooks
        - .url: The shareable URL
        - .metadata: Snapshot metadata (id, title, visibility)

    Raises:
        UploadError: If upload to Skua API fails
        SerializationError: If object cannot be serialized

    Examples:
        Basic usage:
        >>> skua.snap(fig, title="Q3 Revenue")
        ✓ swift-gannet-4291 · Q3 Revenue → https://skua.dev/s/abc123 (private)

        Public override:
        >>> skua.snap(fig, title="Q3 Revenue", public=True)
        ✓ swift-gannet-4291 · Q3 Revenue → https://skua.dev/s/abc123 (public)

        Session default via configure():
        >>> skua.configure(public=True)
        >>> skua.snap(fig, title="Revenue")  # uses public default
        ✓ swift-gannet-4291 · Revenue → https://skua.dev/s/abc123 (public)
    """
    from skua.exceptions import ValidationError

    if obj is None:
        raise ValidationError(
            "Cannot snap None. "
            "Pass a matplotlib figure, pandas DataFrame, PIL Image, or other object."
        )
    if not title or not title.strip():
        raise ValidationError("Title is required.")
    if len(title) > 500:
        raise ValidationError(
            f"Title too long ({len(title)} characters). Maximum: 500 characters."
        )
    if description and len(description) > 1000:
        raise ValidationError(
            f"Description too long ({len(description)} characters). Maximum: 1000 characters."
        )

    # Clean and validate tags
    clean_tags: list[str] = []
    if tags:
        clean_tags = [t.strip() for t in tags if t.strip()]
        if len(clean_tags) > 20:
            raise ValidationError(
                f"Too many tags ({len(clean_tags)}). Maximum: 20 tags."
            )
        for tag in clean_tags:
            if len(tag) > 50:
                raise ValidationError(
                    f"Tag too long ({len(tag)} characters): '{tag[:20]}...'. Maximum: 50 characters."
                )

    # Resolve visibility: per-call > configure() default > None (server decides)
    if public is not None:
        visibility = "public" if public else "private"
    elif (session_public := get_session_public()) is not None:
        visibility = "public" if session_public else "private"
    else:
        visibility = None  # Server applies its own default

    serialized = serialize_object(obj)

    snapshot_data = {
        "content": serialized,
        "title": title.strip(),
        "description": description,
        "visibility": visibility,
        "tags": clean_tags,
    }

    result = upload_snapshot(snapshot_data)

    snapshot_id = result["id"]
    creator_username = result.get("creator_username")
    applied_visibility = result.get("visibility", "public")

    url = f"{get_web_url()}/s/{snapshot_id}"

    # Print success line: ✓ username · Title → URL (visibility)
    if creator_username:
        print(f"✓ {creator_username} · {title.strip()} → {url} ({applied_visibility})")
    else:
        print(f"✓ {title.strip()} → {url} ({applied_visibility})")

    metadata = {
        "id": snapshot_id,
        "title": title.strip(),
        "visibility": applied_visibility,
    }

    return SnapResult(obj=obj, url=url, metadata=metadata)


# Backward compatibility alias
record = snap
