"""Visual flow: identify every table by looking at the rendered page.

Renders each page and runs the grid locator on it; the located full-anatomy
boxes ARE the table count and identity for the document. No Camelot, no
detector, no recovery. Pages are processed concurrently under a small
semaphore so the per-page vision calls overlap without flooding the API.
"""

from __future__ import annotations

import asyncio
import tempfile
from pathlib import Path
from typing import List

from quber.agents.grid_locator import GridLocator
from quber.core.extractors.camelot.acquire import render_pages
from quber.core.extractors.dual.models import VisualTable


async def run_vision_flow(
    source: Path,
    locator: GridLocator,
    dpi: int = 200,
    concurrency: int = 4,
) -> List[VisualTable]:
    """Locate tables on every page of `source` and return them in page order."""
    with tempfile.TemporaryDirectory(prefix="quber-dual-vision-") as tmp:
        page_images = await asyncio.to_thread(render_pages, source, dpi, Path(tmp))
        semaphore = asyncio.Semaphore(concurrency)

        async def locate_page(page: int, image: Path) -> List[VisualTable]:
            async with semaphore:
                located = await locator.locate(image, source, page)
            return [
                VisualTable(
                    page=page,
                    ordinal=t.ordinal,
                    title=t.title,
                    region=t.region,
                    tightened=t.tightened,
                )
                for t in located
            ]

        per_page = await asyncio.gather(
            *(locate_page(i, image) for i, image in enumerate(page_images, start=1))
        )
    return [table for page_tables in per_page for table in page_tables]
