#!/usr/bin/env python3
"""Generate 2-level terrain: level 0=flat, level 1=pyramid stairs.

1cm = 1px. OpenCV draws concentric filled rectangles (outside→in, 10 steps).
Higher values overwrite lower = convex pyramid (stairs up toward center).
Lower values overwrite higher = concave pyramid (stairs down from center).

Usage:
    uv run scripts/gen_flat_stairs.py                        # convex (stairs UP)
    uv run scripts/gen_flat_stairs.py --concave              # concave (stairs DOWN)
    uv run scripts/gen_flat_stairs.py --step-h 0.10 --num-steps 5
"""
import cv2, numpy as np, os, argparse

# ═══ fixed params ═══
HS = 0.01             # 1cm/px
VS = 0.005            # height unit = 0.5cm
CELL_M = 8.0          # 8m cell
BORDER_M = 5.0        # 5m border
NUM_ROWS = 2          # flat + stairs
NUM_COLS = 4          # columns

CELL_PX = int(CELL_M / HS)       # 800
BORDER_PX = int(BORDER_M / HS)   # 500
PLATFORM_PX = int(1.0 / HS)      # 1m platform = 100px

TOT_ROWS = NUM_ROWS * CELL_PX + 2 * BORDER_PX
TOT_COLS = NUM_COLS * CELL_PX + 2 * BORDER_PX

# ═══ stairs params (override via CLI) ═══
NUM_STEPS = 10        # 10 steps
STEP_H_CM = 20        # 20cm rise per step
STEP_D_CM = 20        # 20cm tread per step

STEP_H_VS = int(STEP_H_CM / 100.0 / VS)  # 0.20 / 0.005 = 40
STEP_D_PX = int(STEP_D_CM / 100.0 / HS)  # 0.20 / 0.01 = 20


def draw_pyramid(canvas, x0, y0, num_steps, step_d_px, step_h_vs, concave=False):
    """Draw concentric rectangles from outside→in.

    Convex: edge=0 → platform=max (stairs up toward center)
    Concave: raise whole cell to max, then draw pit: edge=max → platform=0
    """
    cx, cy = x0 + CELL_PX // 2, y0 + CELL_PX // 2
    p2 = PLATFORM_PX // 2
    h_max = step_h_vs * num_steps

    # Fill cell to cell boundary with reference-plane height
    half_max = CELL_PX // 2  # extend to cell edge
    cv2.rectangle(canvas, (cx - half_max, cy - half_max),
                  (cx + half_max, cy + half_max), int(h_max), -1)

    if concave:
        # Pit: rings going DOWN from reference plane
        for i in range(num_steps + 1):
            half = p2 + (num_steps - i) * step_d_px
            x1, y1 = cx - half, cy - half
            x2, y2 = cx + half, cy + half
            h = h_max - step_h_vs * i
            cv2.rectangle(canvas, (x1, y1), (x2, y2), int(h), -1)
    else:
        # Mound: rings going UP from reference plane
        for i in range(num_steps + 1):
            half = p2 + (num_steps - i) * step_d_px
            x1, y1 = cx - half, cy - half
            x2, y2 = cx + half, cy + half
            h = h_max + step_h_vs * i
            cv2.rectangle(canvas, (x1, y1), (x2, y2), int(h), -1)


def main():
    p = argparse.ArgumentParser()
    p.add_argument("--concave", action="store_true", help="concave pyramid (stairs down from center)")
    p.add_argument("--step-h", type=float, default=0.20, help="step rise (m)")
    p.add_argument("--step-d", type=float, default=0.20, help="step tread (m)")
    p.add_argument("--num-steps", type=int, default=10, help="number of steps")
    args = p.parse_args()

    step_h_vs = int(args.step_h / VS)
    step_d_px = int(args.step_d / HS)
    total_h = step_h_vs * args.num_steps * VS

    print(f"Building {TOT_COLS}×{TOT_ROWS}px ({TOT_COLS*HS:.0f}×{TOT_ROWS*HS:.0f}m)")
    print(f"  type={'concave' if args.concave else 'convex'}  "
          f"steps={args.num_steps}  rise={step_h_vs*VS*100:.0f}cm  "
          f"tread={step_d_px*HS*100:.0f}cm  total_h={total_h*100:.0f}cm")

    canvas = np.zeros((TOT_ROWS, TOT_COLS), dtype=np.uint16)

    for row in range(NUM_ROWS):
        for col in range(NUM_COLS):
            x0 = BORDER_PX + col * CELL_PX
            y0 = BORDER_PX + row * CELL_PX
            if row == 1:
                # alternate convex/concave across cols
                concave_cell = (col % 2 == 1)
                draw_pyramid(canvas, x0, y0, args.num_steps,
                             step_d_px, step_h_vs, concave_cell)

    hf_m = canvas.astype(np.float32) * VS
    z_min, z_max = float(hf_m.min()), float(hf_m.max())
    z_range = max(z_max - z_min, 0.001)

    png = ((hf_m - z_min) / z_range * 65535).astype(np.uint16)

    out_dir = os.path.join(os.path.dirname(__file__), "..",
                           "motrix_envs", "src", "motrix_envs", "locomotion",
                           "go1", "xmls", "assets")
    os.makedirs(out_dir, exist_ok=True)
    out_path = os.path.join(out_dir, "flat_stairs.png")
    cv2.imwrite(out_path, png)
    print(f"  saved: {out_path}")
    print(f"  XML: size=\"{TOT_COLS*HS/2:.1f} {TOT_ROWS*HS/2:.1f} "
          f"{z_range:.3f} {max(z_min,0.001):.3f}\"")


if __name__ == "__main__":
    main()
