"""
MBTiles management — download and serve map tiles from SQLite.
"""

from __future__ import annotations

import sqlite3
import time

import httpx


def get_tile(conn: sqlite3.Connection, z: int, x: int, y: int) -> bytes | None:
    """Retrieve a tile from the database (XYZ scheme, converted to TMS internally)."""
    y_tms = (1 << z) - 1 - y
    row = conn.execute(
        "SELECT tile_data FROM tiles WHERE zoom_level=? AND tile_column=? AND tile_row=?",
        (z, x, y_tms),
    ).fetchone()
    return row[0] if row else None


def tile_count(conn: sqlite3.Connection) -> int:
    row = conn.execute("SELECT COUNT(*) FROM tiles").fetchone()
    return row[0]


def download_tiles(
    conn: sqlite3.Connection,
    bbox: tuple[float, float, float, float],
    zoom_min: int = 6,
    zoom_max: int = 14,
    tile_url: str = "https://tile.openstreetmap.org/{z}/{x}/{y}.png",
    progress=None,
) -> int:
    """Download map tiles for a bounding box into the database.

    Args:
        conn: Open SQLite connection.
        bbox: (lon_min, lat_min, lon_max, lat_max).
        zoom_min: Minimum zoom level.
        zoom_max: Maximum zoom level.
        tile_url: Tile URL template with {z}, {x}, {y} placeholders.
        progress: Optional callable(message, current, total).

    Returns:
        Number of tiles downloaded.
    """
    try:
        import mercantile
    except ImportError:
        raise ImportError("Install tiles extra: pip install yoro-maps[tiles]")

    conn.execute("INSERT OR REPLACE INTO metadata VALUES ('format', 'png')")

    total_tiles = 0
    for z in range(zoom_min, zoom_max + 1):
        total_tiles += len(list(mercantile.tiles(*bbox, zooms=z)))

    downloaded = 0
    client = httpx.Client(
        timeout=15,
        headers={"User-Agent": "yoromaps/0.1 (https://github.com/Altius-Academy-SNC/yoro-maps)"},
        follow_redirects=True,
    )

    try:
        for z in range(zoom_min, zoom_max + 1):
            tiles = list(mercantile.tiles(*bbox, zooms=z))
            for t in tiles:
                # Skip if already exists
                y_tms = (1 << t.z) - 1 - t.y
                existing = conn.execute(
                    "SELECT 1 FROM tiles WHERE zoom_level=? AND tile_column=? AND tile_row=?",
                    (t.z, t.x, y_tms),
                ).fetchone()
                if existing:
                    downloaded += 1
                    continue

                url = tile_url.format(z=t.z, x=t.x, y=t.y)
                try:
                    resp = client.get(url)
                    if resp.status_code == 200:
                        conn.execute(
                            "INSERT OR REPLACE INTO tiles VALUES (?, ?, ?, ?)",
                            (t.z, t.x, y_tms, resp.content),
                        )
                except httpx.HTTPError:
                    pass

                downloaded += 1
                if progress and downloaded % 50 == 0:
                    progress(f"z={z}", downloaded, total_tiles)

                # Rate limiting
                time.sleep(0.05)

            conn.commit()
    finally:
        client.close()

    if progress:
        progress("Done", downloaded, total_tiles)

    return downloaded
