"""read_pdf — Extract text and metadata from PDF files.

Uses PyMuPDF (fitz) — MIT-licensed, fast, handles complex multi-column PDFs.
Install: pip install pymupdf  (or pip install "fliiq[pdf]")

Supports:
  - Local file paths
  - Remote URLs (with Content-Type validation and size cap)
  - Page range selection
  - Encrypted PDF detection with clear error messages
  - Structured output (per-page) or full_text concatenation
"""

from __future__ import annotations

from pathlib import Path
from typing import Any


def read_pdf(
    path: str | None = None,
    url: str | None = None,
    pages: list[int] | None = None,
    mode: str = "structured",
    max_size_mb: int = 50,
) -> dict[str, Any]:
    """Extract text and metadata from a PDF file or URL.

    Args:
        path: Local file path to PDF. Use this OR url.
        url: Remote URL of a PDF. Use this OR path.
        pages: List of 1-based page numbers to extract. None = all pages.
        mode: 'structured' (list of {page_num, text}) or 'full_text' (string).
        max_size_mb: Max download size in MB for URL fetching. Default 50.

    Returns:
        dict with:
            title: PDF title metadata (may be empty string)
            author: PDF author metadata (may be empty string)
            page_count: total number of pages in the document
            pages: list of {page_num, text} dicts (if mode='structured')
            full_text: concatenated text of all requested pages
            source: the path or URL used
            error: error message if something went wrong (key absent on success)
    """
    try:
        import fitz  # PyMuPDF  # type: ignore[import]
    except ImportError:
        return {
            "error": (
                "PyMuPDF is required for read_pdf. "
                "Install it with: pip install pymupdf  "
                "or: pip install 'fliiq[pdf]'"
            ),
            "pages": [],
            "full_text": "",
            "page_count": 0,
            "title": "",
            "author": "",
        }

    if not path and not url:
        return {
            "error": "Either 'path' or 'url' must be provided.",
            "pages": [],
            "full_text": "",
            "page_count": 0,
            "title": "",
            "author": "",
        }

    if path and url:
        return {
            "error": "Provide either 'path' or 'url', not both.",
            "pages": [],
            "full_text": "",
            "page_count": 0,
            "title": "",
            "author": "",
        }

    mode = mode if mode in ("structured", "full_text") else "structured"
    max_bytes = max_size_mb * 1024 * 1024

    # --- Load PDF bytes ---
    pdf_bytes: bytes | None = None
    source: str = ""

    if path:
        source = path
        p = Path(path)
        if not p.exists():
            return {
                "error": f"File not found: {path}",
                "pages": [],
                "full_text": "",
                "page_count": 0,
                "title": "",
                "author": "",
                "source": source,
            }
        if not p.is_file():
            return {
                "error": f"Path is not a file: {path}",
                "pages": [],
                "full_text": "",
                "page_count": 0,
                "title": "",
                "author": "",
                "source": source,
            }
        file_size = p.stat().st_size
        if file_size > max_bytes:
            return {
                "error": (
                    f"File too large: {file_size / 1024 / 1024:.1f} MB "
                    f"(limit: {max_size_mb} MB). Use pages= to extract specific pages."
                ),
                "pages": [],
                "full_text": "",
                "page_count": 0,
                "title": "",
                "author": "",
                "source": source,
            }
        pdf_bytes = p.read_bytes()

    elif url:
        source = url
        try:
            import httpx  # type: ignore[import]
        except ImportError:
            return {
                "error": "httpx is required for URL-based PDF fetching. Install: pip install httpx",
                "pages": [],
                "full_text": "",
                "page_count": 0,
                "title": "",
                "author": "",
                "source": source,
            }

        try:
            with httpx.Client(follow_redirects=True, timeout=30.0) as client:
                # HEAD request first to check Content-Type and size
                try:
                    head = client.head(url)
                    content_type = head.headers.get("content-type", "")
                    content_length = int(head.headers.get("content-length", 0))

                    if content_length > max_bytes:
                        return {
                            "error": (
                                f"Remote PDF too large: {content_length / 1024 / 1024:.1f} MB "
                                f"(limit: {max_size_mb} MB). Use pages= to extract specific pages."
                            ),
                            "pages": [],
                            "full_text": "",
                            "page_count": 0,
                            "title": "",
                            "author": "",
                            "source": source,
                        }

                    # Validate Content-Type (allow application/pdf and application/octet-stream)
                    ct_lower = content_type.lower() if content_type else ""
                    if content_type and "pdf" not in ct_lower and "octet-stream" not in ct_lower:
                        return {
                            "error": (
                                f"URL does not appear to be a PDF. "
                                f"Content-Type: '{content_type}'. "
                                f"Expected 'application/pdf'."
                            ),
                            "pages": [],
                            "full_text": "",
                            "page_count": 0,
                            "title": "",
                            "author": "",
                            "source": source,
                        }
                except httpx.HTTPError:
                    # HEAD not supported — fall through to GET
                    pass

                # GET the PDF
                response = client.get(url)
                response.raise_for_status()

                # Re-check content type from GET response
                ct = response.headers.get("content-type", "")
                if ct and "pdf" not in ct.lower() and "octet-stream" not in ct.lower() and "html" in ct.lower():
                    return {
                        "error": (
                            f"URL returned HTML, not a PDF. Content-Type: '{ct}'. "
                            f"Check the URL points directly to a .pdf file."
                        ),
                        "pages": [],
                        "full_text": "",
                        "page_count": 0,
                        "title": "",
                        "author": "",
                        "source": source,
                    }

                pdf_bytes = response.content
                if len(pdf_bytes) > max_bytes:
                    return {
                        "error": (
                            f"Downloaded PDF too large: {len(pdf_bytes) / 1024 / 1024:.1f} MB "
                            f"(limit: {max_size_mb} MB)."
                        ),
                        "pages": [],
                        "full_text": "",
                        "page_count": 0,
                        "title": "",
                        "author": "",
                        "source": source,
                    }

        except Exception as e:
            return {
                "error": f"Failed to download PDF from URL: {e}",
                "pages": [],
                "full_text": "",
                "page_count": 0,
                "title": "",
                "author": "",
                "source": source,
            }

    # --- Open with PyMuPDF ---
    try:
        doc = fitz.open(stream=pdf_bytes, filetype="pdf")
    except Exception as e:
        return {
            "error": f"Failed to open PDF: {e}",
            "pages": [],
            "full_text": "",
            "page_count": 0,
            "title": "",
            "author": "",
            "source": source,
        }

    # Check for encryption
    if doc.is_encrypted:
        doc.close()
        return {
            "error": (
                "This PDF is encrypted/password-protected and cannot be read. "
                "Please provide an unencrypted version."
            ),
            "pages": [],
            "full_text": "",
            "page_count": 0,
            "title": "",
            "author": "",
            "source": source,
        }

    # Extract metadata
    meta = doc.metadata or {}
    title = meta.get("title", "") or ""
    author = meta.get("author", "") or ""
    total_pages = doc.page_count

    # Determine which pages to extract (1-based input → 0-based index)
    if pages:
        # Validate and convert page numbers
        page_indices = []
        for p_num in pages:
            if 1 <= p_num <= total_pages:
                page_indices.append(p_num - 1)
            # Silently skip out-of-range pages
    else:
        page_indices = list(range(total_pages))

    # Extract text
    extracted_pages: list[dict] = []
    for idx in page_indices:
        page = doc[idx]
        text = page.get_text("text").strip()
        extracted_pages.append({
            "page_num": idx + 1,
            "text": text,
        })

    doc.close()

    full_text = "\n\n".join(p["text"] for p in extracted_pages if p["text"])

    result: dict[str, Any] = {
        "title": title,
        "author": author,
        "page_count": total_pages,
        "pages_extracted": len(extracted_pages),
        "full_text": full_text,
        "source": source,
    }

    if mode == "structured":
        result["pages"] = extracted_pages
    else:
        result["pages"] = []

    return result


async def handler(params: dict) -> dict:
    """Skill entry point — delegates to read_pdf()."""
    return read_pdf(**params)
