"""Restaurant: tileable surface textures for the 3D bridge.

After assets/story/intro/07_kitchen_single.png — the hero's own kitchen: white
subway tiles, a steel counter, a doorway onto a small dining room — and the
street it opens onto. Muted, slightly worn, never glossy-new.

Reuses the periodic noise and save helpers of crater_meadow_textures.py.

Run headless from big-egg-3d/:
  blender --background --factory-startup --python tools/blender/restaurant_textures.py
"""
import os, sys
import numpy as np

sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
import crater_meadow_textures as base  # noqa: E402

base.OUT = os.path.join(base.PROJECT, "assets", "textures", "restaurant")
hex_rgb = base.hex_rgb
noise = base.periodic_noise


def grid_tiles(size, cols, rows, grout, colors, seed, stagger=False, bevel=0.1, grime=0.0):
    """Tiles with grout lines; each tile gets its own shade."""
    r = np.random.default_rng(seed)
    tw, th = size // cols, size // rows
    yy, xx = np.mgrid[0:size, 0:size]
    row = yy // th
    shift = np.where((row % 2 == 1) & stagger, tw // 2, 0)
    col = ((xx + shift) // tw) % cols
    lx = (xx + shift) % tw
    ly = yy % th
    ids = row * cols + col
    palette = np.array([colors[i % len(colors)] for i in range(cols * rows)])
    palette *= r.uniform(0.93, 1.05, (cols * rows, 1))
    img = palette[ids % (cols * rows)]
    # Soft bevel: tiles darken slightly toward their edges.
    edge = np.minimum(np.minimum(lx, tw - 1 - lx) / tw, np.minimum(ly, th - 1 - ly) / th)
    img = img * (1.0 - bevel * np.clip(0.12 - edge, 0, 0.12)[..., None] / 0.12)
    joint = (lx < grout) | (ly < grout)
    img[joint] = grout_color = hex_rgb("#7d7a72")
    if grime:
        n = noise(size, 1.2, seed + 1)[..., None]
        near = np.clip(1.0 - edge * 8.0, 0, 1)[..., None]
        img = img * (1.0 - grime * n * (0.4 + 0.6 * near))
    return img, joint


def kitchen_floor():
    img, joint = grid_tiles(512, 8, 8, 3, [hex_rgb("#c9c6bd"), hex_rgb("#bdb9af"), hex_rgb("#d2cfc6")], 31, grime=0.12)
    img[joint] = hex_rgb("#5e5b55")
    # A few darker stains where cooks stand.
    stain = noise(512, 2.0, 32)[..., None]
    img = img * (1.0 - 0.1 * np.clip(stain - 0.6, 0, 1) / 0.4)
    base.save("kitchen_floor", img)


def dining_wood():
    size = 1024
    r = np.random.default_rng(41)
    rows = 8
    th = size // rows
    img = np.zeros((size, size, 3))
    grain = noise(size, 1.1, 42)
    # Stretch the grain along the planks.
    grain = np.repeat(grain[::8, :], 8, axis=0)[:size]
    woods = [hex_rgb(h) for h in ("#7a5236", "#6d4830", "#835a3c", "#734d33", "#8a6142")]
    for k in range(rows):
        y0 = k * th
        start = x = int(r.integers(0, size))
        while x - start < size:
            length = int(r.integers(size // 4, size // 2))
            colour = woods[int(r.integers(0, len(woods)))] * r.uniform(0.9, 1.08)
            for dx in range(length):
                xi = (x + dx) % size
                img[y0:y0 + th, xi] = colour
            # Plank end joint.
            img[y0:y0 + th, (x + length) % size] = hex_rgb("#2c1d13")
            x += length + 1
        img[y0:y0 + 2, :] = hex_rgb("#2c1d13")
    img = img * (0.82 + 0.3 * grain[..., None])
    wear = noise(size, 1.8, 43)[..., None]
    img = img * (0.9 + 0.18 * wear)
    base.save("dining_wood", img)


def linoleum():
    size = 512
    yy, xx = np.mgrid[0:size, 0:size]
    check = ((xx // 64) + (yy // 64)) % 2
    a, b = hex_rgb("#cbc3ae"), hex_rgb("#7d857d")
    img = np.where(check[..., None] == 0, a, b)
    n = noise(size, 1.3, 51)[..., None]
    img = img * (0.86 + 0.2 * n)
    base.save("linoleum", img)


def subway():
    img, joint = grid_tiles(512, 4, 8, 3, [hex_rgb("#e4e2dc"), hex_rgb("#dcdad3"), hex_rgb("#e9e7e1")], 61, stagger=True, bevel=0.25, grime=0.12)
    img[joint] = hex_rgb("#9a978f")
    base.save("subway_tile", img)


def plaster():
    n1 = noise(512, 1.5, 71)[..., None]
    n2 = noise(512, 0.8, 72)[..., None]
    img = hex_rgb("#d9cbb0") * (0.9 + 0.12 * n1) * (0.96 + 0.06 * n2)
    base.save("plaster", img)


def wainscot():
    size = 512
    xx = np.mgrid[0:size, 0:size][1]
    board = (xx // 64) % 2
    img = np.where(board[..., None] == 0, hex_rgb("#3e5049"), hex_rgb("#394a43"))
    img = img.astype(float)
    img[:, xx[0] % 64 < 3] = hex_rgb("#1f2a26")
    n = noise(size, 1.2, 81)[..., None]
    img = img * (0.88 + 0.2 * n)
    base.save("wainscot", img)


def brick():
    img, joint = grid_tiles(512, 4, 16, 4, [hex_rgb(h) for h in ("#7b3f2f", "#6e3829", "#864736", "#733e30", "#5f3327")], 91, stagger=True, bevel=0.2, grime=0.2)
    img[joint] = hex_rgb("#8d857a")
    soot = noise(512, 1.6, 92)[..., None]
    img = img * (0.8 + 0.25 * soot)
    base.save("brick", img)


def concrete():
    """Sidewalk slabs: large squares, speckled, a few stains."""
    size = 512
    n1 = noise(size, 1.4, 101)[..., None]
    n2 = noise(size, 0.5, 102)[..., None]
    img = hex_rgb("#8e8c86") * (0.85 + 0.2 * n1) * (0.94 + 0.1 * n2)
    yy, xx = np.mgrid[0:size, 0:size]
    joint = (xx % 256 < 3) | (yy % 256 < 3)
    img[joint] = hex_rgb("#5a5853")
    base.stamp_blobs(img, 18, (4, 14), hex_rgb("#6f6d67"), hex_rgb("#6f6d67"), 103)
    base.save("concrete", img)


def asphalt():
    size = 512
    n1 = noise(size, 1.2, 111)[..., None]
    n2 = noise(size, 0.4, 112)[..., None]
    img = hex_rgb("#2e2d30") * (0.8 + 0.35 * n1) * (0.85 + 0.3 * n2)
    specks = np.random.default_rng(113).random((size, size)) < 0.03
    img[specks] = hex_rgb("#58565a")
    base.stamp_strokes(img, 60, (10, 40), 2, np.array([hex_rgb("#1a191b")]), 0.05, 114)
    base.save("asphalt", img)


def roof():
    size = 512
    n = noise(size, 0.3, 121)[..., None]
    img = hex_rgb("#403e3c") * (0.75 + 0.5 * n)
    specks = np.random.default_rng(122).random((size, size)) < 0.08
    img[specks] = img[specks] * 1.35
    base.save("roof_gravel", img)


if __name__ == "__main__":
    os.makedirs(base.OUT, exist_ok=True)
    for make in (kitchen_floor, dining_wood, linoleum, subway, plaster, wainscot, brick, concrete, asphalt, roof):
        make()
