"""Format ihyee SDK responses into clean text for LLM consumption."""
from __future__ import annotations

from typing import List

from ihyee.models import ContentItem, FetchResponse, RagContent, SearchResponse


def _format_links(item: ContentItem) -> str:
    """Format extracted links from a content item."""
    if not item.text or not item.text.links:
        return ""

    lines: list[str] = []
    for link in item.text.links[:10]:  # Cap at 10 links per result
        label = link.text.strip() or link.context.strip() or "Link"
        lines.append(f"  - {label}: {link.url}")

    if not lines:
        return ""
    return "**Links:**\n" + "\n".join(lines) + "\n"


def _format_rag_content(rag: RagContent, index: int | None = None) -> str:
    """Format a RagContent object into readable text."""
    parts: list[str] = []

    # Header
    header = f"### {rag.title}" if rag.title else "### (untitled)"
    if index is not None:
        header = f"### {index}. {rag.title or '(untitled)'}"
    parts.append(header)

    # Metadata
    meta_parts: list[str] = []
    if rag.author and rag.author != "Unknown":
        meta_parts.append(f"**Author:** {rag.author}")
    if rag.date_published:
        meta_parts.append(f"**Published:** {rag.date_published}")
    meta_parts.append(f"**Relevance:** {rag.relevance_score:.2f}")
    meta_parts.append(f"**Tokens:** {rag.total_tokens}")
    parts.append(" | ".join(meta_parts))

    # Chunks
    for ci, chunk in enumerate(rag.chunks, start=1):
        heading_path = " > ".join(chunk.heading_path) if chunk.heading_path else ""
        chunk_header = f"**Chunk {ci}**"
        if heading_path:
            chunk_header += f" ({heading_path})"
        chunk_header += f" [score={chunk.relevance_score:.2f}, {chunk.token_count} tokens]"
        parts.append(chunk_header)
        parts.append(chunk.content)

        if chunk.citations:
            cite_lines = [f"  - {c.text}: {c.url}" for c in chunk.citations[:5]]
            parts.append("Citations:\n" + "\n".join(cite_lines))

    # Links
    if rag.links:
        link_lines = []
        for link in rag.links[:10]:
            label = link.text.strip() or link.context.strip() or "Link"
            link_lines.append(f"  - {label}: {link.url}")
        if link_lines:
            parts.append("**Links:**\n" + "\n".join(link_lines))

    return "\n".join(parts)


def _format_content_item(item: ContentItem, index: int | None = None) -> str:
    """Format a single ContentItem into readable text."""
    # RAG content items have a different structure
    if item.rag is not None:
        return _format_rag_content(item.rag, index=index)

    parts: list[str] = []

    # Header with index and URL
    if index is not None and item.url:
        parts.append(f"### {index}. {item.url}")
    elif item.url:
        parts.append(f"### {item.url}")

    if not item.text:
        if item.type == "image" and item.image_url:
            parts.append(f"**Image:** {item.image_url.url}")
            if item.image_url.alt:
                parts.append(f"**Alt text:** {item.image_url.alt}")
        elif item.type == "document" and item.document:
            parts.append(f"**Document:** {item.document.original_url}")
            parts.append(f"**Type:** {item.document.content_type}")
            parts.append(f"**Size:** {item.document.size_bytes:,} bytes")
        return "\n".join(parts)

    text = item.text

    # Error case
    if text.error:
        parts.append(f"**Error:** {text.error}")
        return "\n".join(parts)

    # Metadata
    meta_parts: list[str] = []
    if text.author and text.author != "Unknown":
        meta_parts.append(f"**Author:** {text.author}")
    if text.date_published and text.date_published != "Unknown":
        meta_parts.append(f"**Published:** {text.date_published}")
    if meta_parts:
        parts.append(" | ".join(meta_parts))

    # Summary
    if text.summary:
        parts.append(f"\n{text.summary}")

    # Full text (truncated for readability)
    if text.full_text:
        full = text.full_text.strip()
        if text.summary:
            # If we already have a summary, show full text under a heading
            if len(full) > 3000:
                full = full[:3000] + "\n\n[... truncated]"
            parts.append(f"\n**Full text:**\n{full}")
        else:
            # No summary — full text is the main content
            if len(full) > 5000:
                full = full[:5000] + "\n\n[... truncated]"
            parts.append(f"\n{full}")

    # Links
    links_text = _format_links(item)
    if links_text:
        parts.append(f"\n{links_text}")

    return "\n".join(parts)


def _format_rag_meta(meta) -> str:
    """Format RAG-specific metadata fields."""
    parts: list[str] = []
    if meta.total_chunks is not None:
        parts.append(f"Total chunks: {meta.total_chunks}")
    if meta.total_tokens is not None:
        parts.append(f"Total tokens: {meta.total_tokens}")
    return " | ".join(parts) if parts else ""


def format_search_response(response: SearchResponse) -> str:
    """Format a SearchResponse into readable text for an LLM."""
    parts: list[str] = []

    parts.append(f"## Search Results for \"{response.query}\"")
    parts.append(f"*{response.results_count} results found*\n")

    for i, item in enumerate(response.content, start=1):
        parts.append(_format_content_item(item, index=i))
        parts.append("")  # blank line between results

    # Meta info
    meta = response.meta
    meta_parts: list[str] = []
    if meta.search_time_ms is not None:
        meta_parts.append(f"Search time: {meta.search_time_ms}ms")
    meta_parts.append(f"Pages fetched: {meta.pages_fetched}")
    if meta.pages_rendered > 0:
        meta_parts.append(f"Pages rendered: {meta.pages_rendered}")
    if meta.degraded:
        meta_parts.append("Note: Some results may be degraded")
    if meta.render_skipped:
        meta_parts.append(f"Render skipped: {meta.render_skipped}")

    # RAG metadata
    rag_meta = _format_rag_meta(meta)
    if rag_meta:
        meta_parts.append(rag_meta)

    parts.append(f"---\n*{' | '.join(meta_parts)}*")

    return "\n".join(parts)


def format_fetch_response(response: FetchResponse, label: str = "Fetched Content") -> str:
    """Format a FetchResponse into readable text for an LLM."""
    parts: list[str] = []

    parts.append(f"## {label}")
    parts.append(f"*{len(response.content)} page(s) processed*\n")

    for i, item in enumerate(response.content, start=1):
        parts.append(_format_content_item(item, index=i))
        parts.append("")  # blank line between results

    # Meta info
    meta = response.meta
    meta_parts: list[str] = []
    meta_parts.append(f"Pages fetched: {meta.pages_fetched}")
    if meta.pages_rendered > 0:
        meta_parts.append(f"Pages rendered: {meta.pages_rendered}")
    if meta.degraded:
        meta_parts.append("Note: Some results may be degraded")
    if meta.render_skipped:
        meta_parts.append(f"Render skipped: {meta.render_skipped}")

    # RAG metadata
    rag_meta = _format_rag_meta(meta)
    if rag_meta:
        meta_parts.append(rag_meta)

    parts.append(f"---\n*{' | '.join(meta_parts)}*")

    return "\n".join(parts)
