from PIL import Image
import sys
from dataclasses import dataclass
from generate import renderer
from os import path

visited = set()

@dataclass
class vec3:
    x: float
    y: float
    z: float

@dataclass
class Platform:
    scale: vec3
    position: vec3

def parse_width(x, y, get_pixel):
    width = 0
    while True:
        px = get_pixel(x, y)
        if px[0] != 0:
            width += 1
            x += 1
        else:
            break
    return width

def parse_height(x, y, get_pixel):
    height = 0
    while True:
        px = get_pixel(x, y)
        if px[0] != 0:
            height += 1
            y += 1
        else:
            break
    return height

def round_to_one(n):
    if n == 0:
        return 1
    else:
        return n

def visit_pixels(x, y, width, height):
    for yi in range(round_to_one(height)):
        for xi in range(round_to_one(width)):
            xx = x + xi
            yy = y + yi
            location = (xx, yy)
            if location in visited:
                print(location)
            assert location not in visited
            visited.add(location)

def parse_platform(x, y, get_pixel):
    width = parse_width(x, y, get_pixel)
    height = parse_height(x, y, get_pixel)

    visit_pixels(x, y, width, height)

    if width != 0 and height != 0:
        px = get_pixel(x, y)
        position = vec3(
            x + (width / 2),
            (px[0] - 128),
            y + (height / 2),
        )
        scale = vec3(
            width,
            1,
            height,
        )

        return Platform(
            position=position,
            scale=scale,
        )
    else:
        return None

def find_platforms(im):
    width, height = im.size
    pixels = im.convert("RGB").getdata()

    def get_pixel(x, y):
        return pixels[y * width + x]

    platforms = []

    for y in range(height):
        for x in range(width):
            if (x, y) not in visited:
                platform = parse_platform(x, y, get_pixel)
                if platform is not None:
                    platforms.append(platform)

    return platforms

def format_vec3(v):
    return ", ".join((
        f"{n: 8.03f}"
        for n in [v.x, v.y, v.z]
    ))

def generate_platform(platform):
    yield "{"
    yield f".position = vec3({format_vec3(platform.position)}),"
    yield f".scale    = vec3({format_vec3(platform.scale)}),"
    yield "},"

def generate_level(name, platforms):
    yield f"world::platform {name}_platforms[] = {{"
    for platform in platforms:
        yield from generate_platform(platform)
    yield "};"

    yield f"world::level {name}_level = {{"
    yield f".platforms = {name}_platforms,"
    yield f".platforms_length = (sizeof ({name}_platforms)) / (sizeof (world::platform)),"
    yield "};"

def generate_file(name_platforms_list):
    yield '#include "demo/lizard/world.hpp"'
    yield ""
    yield f"namespace demo {{"
    yield ""
    for name, platforms in name_platforms_list:
        yield from generate_level(name, platforms)

    yield ""
    yield '}'

def level_name(p):
    _, fn = path.split(p)
    name, _ = path.splitext(fn)
    return name

def find_all_platforms(maps):
    for filename in maps:
        with Image.open(filename) as im:
            name = level_name(filename)
            platforms = find_platforms(im)
            yield (name, platforms)

maps = sys.argv[1:]

render, out = renderer()
render(generate_file(find_all_platforms(maps)))
sys.stdout.write(out.getvalue())
