#!/usr/bin/env python3
"""Small shared renderer for map thumbnails used by review tools."""
from __future__ import annotations

from render_map_preview import load_tileset_rgb, source_xy


TILESET_CACHE: dict[str, tuple[int, int, bytes, bytes]] = {}


def cached_tileset(name: str) -> tuple[int, int, bytes, bytes]:
    if name not in TILESET_CACHE:
        TILESET_CACHE[name] = load_tileset_rgb(name)
    return TILESET_CACHE[name]


def render_thumbnail(
    info: dict,
    max_width: int,
    max_height: int,
    visual_mode: str = "layer0",
    tile_index_mode: str = "row40_zero",
) -> tuple[int, int, bytes]:
    tile_size = info["tileSize"]
    width = info["width"] * tile_size
    height = info["height"] * tile_size
    scale = min(max_width / width, max_height / height, 1)
    thumb_width = max(1, int(width * scale))
    thumb_height = max(1, int(height * scale))
    out = bytearray((8, 8, 8)) * thumb_width * thumb_height
    layer_tilesets = info.get("layerTilesets") or [info.get("tileset")]
    empty_layer1_tiles = set(info.get("emptyLayer1Tiles") or [])

    def draw_layer(layer: list[int], tileset_name: str, layer_index: int) -> None:
        tileset_width, tileset_height, tileset_rgb, transparent = cached_tileset(tileset_name)
        source_cache: dict[int, tuple[int, int] | None] = {}
        for y in range(thumb_height):
            map_pixel_y = min(height - 1, int(y / scale))
            tile_y = map_pixel_y // tile_size
            local_y = map_pixel_y % tile_size
            for x in range(thumb_width):
                map_pixel_x = min(width - 1, int(x / scale))
                tile_x = map_pixel_x // tile_size
                tile = layer[tile_y * info["width"] + tile_x]
                if tile == 0 or (layer_index > 0 and tile in empty_layer1_tiles):
                    continue
                if tile not in source_cache:
                    source_cache[tile] = source_xy(tile, tile_index_mode, tileset_width, tileset_height, tile_size, info)
                source = source_cache[tile]
                if source is None:
                    continue
                src_x = source[0] + (map_pixel_x % tile_size)
                src_y = source[1] + local_y
                if src_x < 0 or src_y < 0 or src_x >= tileset_width or src_y >= tileset_height:
                    continue
                src = (src_y * tileset_width + src_x) * 3
                color = tileset_rgb[src : src + 3]
                if color == transparent:
                    continue
                dst = (y * thumb_width + x) * 3
                out[dst : dst + 3] = color

    if visual_mode in {"layer0", "bothSceneTilesets", "bothFirstTileset", "layer1UnderSceneTilesets", "layer1UnderFirstTileset"}:
        draw_layer(info["layers"][0], layer_tilesets[0], 0)
    if visual_mode == "layer1UnderSceneTilesets" and len(info["layers"]) > 1:
        draw_layer(info["layers"][1], layer_tilesets[1], 1)
    elif visual_mode == "layer1UnderFirstTileset" and len(info["layers"]) > 1:
        draw_layer(info["layers"][1], layer_tilesets[0], 1)
    if visual_mode == "bothSceneTilesets" and len(info["layers"]) > 1:
        draw_layer(info["layers"][1], layer_tilesets[1], 1)
    elif visual_mode == "bothFirstTileset" and len(info["layers"]) > 1:
        draw_layer(info["layers"][1], layer_tilesets[0], 1)
    return thumb_width, thumb_height, bytes(out)


def background_ratio(rgb: bytes) -> float:
    if not rgb:
        return 0.0
    pixels = len(rgb) // 3
    background = 0
    for offset in range(0, len(rgb), 3):
        if rgb[offset : offset + 3] == b"\x08\x08\x08":
            background += 1
    return background / pixels if pixels else 0.0
