"""Utility helpers for the banner generator: source reading and image saving."""

from __future__ import annotations

import logging
import urllib.error
import urllib.request
from pathlib import Path

from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_exponential

logger = logging.getLogger(__name__)


def read_source(source: str | Path) -> str:
    """Read a local file or fetch content from a GitHub URL.

    GitHub blob URLs are converted to raw.githubusercontent.com automatically.
    Returns empty string on failure (with a warning log).
    """
    path = Path(source)
    if path.exists():
        return path.read_text(encoding="utf-8", errors="replace")

    # Convert GitHub blob URL → raw URL
    url = str(source)
    if "github.com" in url and "raw.githubusercontent.com" not in url:
        url = (
            url.replace("github.com", "raw.githubusercontent.com")
               .replace("/blob/", "/")
        )
    @retry(
        retry=retry_if_exception_type((urllib.error.URLError, OSError, TimeoutError)),
        stop=stop_after_attempt(3),
        wait=wait_exponential(multiplier=1, min=1, max=5),
        reraise=False,
    )
    def _fetch() -> str:
        with urllib.request.urlopen(url, timeout=10) as r:
            return r.read().decode("utf-8", errors="replace")

    try:
        return _fetch()
    except Exception as exc:
        logger.warning("Could not fetch source %s: %s", source, exc)
        return ""


def build_user_context(
    *,
    source: str | Path | None,
    title: str | None,
    description: str | None,
    github_url: str | None,
) -> str:
    """Build a text block describing the project for the LLM system prompt."""
    parts: list[str] = []

    if title:
        parts.append(f"Project name: {title}")
    if description:
        parts.append(f"Description: {description}")

    readme_text = ""
    if source:
        readme_text = read_source(source)
    elif github_url:
        base = github_url.rstrip("/")
        for branch in ("main", "master"):
            url = f"{base}/raw/{branch}/README.md"
            readme_text = read_source(url)
            if readme_text:
                break

    if readme_text:
        # Trim to ~3000 chars to stay within token limits
        parts.append(f"README content (excerpt):\n\n{readme_text[:3000]}")

    if not parts:
        parts.append("A developer tool or Python library.")

    return "\n\n".join(parts)


def save_image(cdn_url: str, output: str | Path) -> Path:
    """Download image from a CDN URL and write it to the output path.

    Creates parent directories automatically.
    Returns the resolved output Path.
    """
    out_path = Path(output)
    out_path.parent.mkdir(parents=True, exist_ok=True)

    @retry(
        retry=retry_if_exception_type((urllib.error.URLError, OSError, TimeoutError)),
        stop=stop_after_attempt(3),
        wait=wait_exponential(multiplier=1, min=2, max=10),
        reraise=True,
    )
    def _download() -> bytes:
        with urllib.request.urlopen(cdn_url, timeout=60) as r:
            return r.read()

    data = _download()

    out_path.write_bytes(data)
    logger.info("Banner saved: %s (%d KB)", out_path, len(data) // 1024)
    return out_path


__all__ = ["read_source", "build_user_context", "save_image"]
