from __future__ import annotations

import base64
import io
import os
import tempfile
import subprocess
import requests
from PIL import Image

OLLAMA_HOST = os.environ.get("DEEPSEEK_OLLAMA_HOST", "http://localhost:11434")
DEEPSEEK_MODEL = os.environ.get("DEEPSEEK_OCR_MODEL", "deepseek-ocr:latest")
DEEPSEEK_PROMPT = os.environ.get("DEEPSEEK_OCR_PROMPT", "<|grounding|>Free OCR.")


def _page_to_image(raw_bytes: bytes, page_num: int = 0) -> bytes | None:
    with tempfile.TemporaryDirectory() as tmpdir:
        result = subprocess.run(
            [
                "pdftoppm", "-png",
                "-f", str(page_num + 1),
                "-l", str(page_num + 1),
                "-",
                os.path.join(tmpdir, "page"),
            ],
            input=raw_bytes,
            capture_output=True,
            timeout=120,
        )
        if result.returncode != 0:
            return None
        out_files = os.listdir(tmpdir)
        if not out_files:
            return None
        img_path = os.path.join(tmpdir, out_files[0])
        img = Image.open(img_path)
        buf = io.BytesIO()
        img.save(buf, format="PNG")
        return buf.getvalue()


def _image_to_text(image_bytes: bytes) -> str:
    b64 = base64.b64encode(image_bytes).decode()
    resp = requests.post(
        f"{OLLAMA_HOST}/api/generate",
        json={
            "model": DEEPSEEK_MODEL,
            "prompt": DEEPSEEK_PROMPT,
            "images": [b64],
            "stream": False,
            "options": {"temperature": 0},
        },
        timeout=120,
    )
    resp.raise_for_status()
    return resp.json().get("response", "")


def ocr_pdf(raw_bytes: bytes, max_pages: int | None = None, page_range: str | None = None) -> dict:
    result = {
        "success": True,
        "text": "",
        "pages": [],
        "page_count": 0,
    }
    pages_to_process = _parse_page_range(page_range, max_pages, raw_bytes)
    for page_num in pages_to_process:
        img_bytes = _page_to_image(raw_bytes, page_num)
        if img_bytes is None:
            continue
        text = _image_to_text(img_bytes)
        result["pages"].append({"page": page_num, "text": text})
        result["text"] += f"\n\n--- PAGE {page_num + 1} ---\n\n{text}"
    result["page_count"] = len(result["pages"])
    return result


def _parse_page_range(page_range: str | None, max_pages: int | None, raw_bytes: bytes) -> list[int]:
    import tempfile, os, subprocess
    total = 0
    with tempfile.NamedTemporaryFile(delete=False, suffix=".pdf") as f:
        f.write(raw_bytes)
        f.flush()
        r = subprocess.run(
            ["pdfinfo", f.name],
            capture_output=True, text=True, timeout=30,
        )
        os.unlink(f.name)
    for line in r.stdout.splitlines():
        if line.startswith("Pages:"):
            total = int(line.split(":")[1].strip())
            break
    if page_range:
        pages = set()
        for part in page_range.split(","):
            part = part.strip()
            if "-" in part:
                a, b = part.split("-", 1)
                for p in range(int(a.strip()), int(b.strip()) + 1):
                    pages.add(p)
            else:
                pages.add(int(part))
        return sorted(pages)
    if max_pages is not None:
        return list(range(min(max_pages, total)))
    return list(range(total))
