from typing import Dict
import json


def amberscript_uniform_buffer_def(uniform_json_contents: str, prefix: str) -> str:
    """
    Returns the string representing AmberScript version of uniform definitions.

    Skips the special '$compute' key, if present.

    {
      "myuniform": {
        "func": "glUniform1f",
        "args": [ 42.0 ],
        "binding": 3
      },
      "$compute": { ... will be ignored ... }
    }

    becomes:

    # uniforms for {prefix}

    # myuniform
    BUFFER {prefix}_myuniform DATA_TYPE float DATA
      42.0
    END

    :param uniform_json_contents:
    :param prefix: E.g. "reference" or "variant". The buffer names will include this prefix to avoid name
    clashes.
    """
    uniform_types: Dict[str, str] = {
        "glUniform1f": "float",
        "glUniform2f": "vec2<float>",
        "glUniform3f": "vec3<float>",
        "glUniform4f": "vec4<float>",
        "glUniform1i": "int32",
        "glUniform2i": "vec2<int32>",
        "glUniform3i": "vec3<int32>",
        "glUniform4i": "vec4<int32>",
        "glUniform1ui": "uint32",
        "glUniform2ui": "vec2<uint32>",
        "glUniform3ui": "vec3<uint32>",
        "glUniform4ui": "vec4<uint32>",
        "glUniform1fv": "float",
        "glUniform2fv": "vec2<float>",
        "glUniform3fv": "vec3<float>",
        "glUniform4fv": "vec4<float>",
        "glUniform1iv": "int32",
        "glUniform2iv": "vec2<int32>",
        "glUniform3iv": "vec3<int32>",
        "glUniform4iv": "vec4<int32>",
        "glUniform1uiv": "int32",
        "glUniform2uiv": "vec2<uint32>",
        "glUniform3uiv": "vec3<uint32>",
        "glUniform4uiv": "vec4<uint32>",
        "glUniformMatrix2fv": "mat2x2<float>",
        "glUniformMatrix3fv": "mat3x3<float>",
        "glUniformMatrix4fv": "mat4x4<float>",
        "glUniformMatrix2x3fv": "mat2x3<float>",
        "glUniformMatrix3x2fv": "mat3x2<float>",
        "glUniformMatrix2x4fv": "mat2x4<float>",
        "glUniformMatrix4x2fv": "mat4x2<float>",
        "glUniformMatrix3x4fv": "mat3x4<float>",
        "glUniformMatrix4x3fv": "mat4x3<float>",
    }

    uniforms = json.loads(uniform_json_contents)

    # If there are no uniforms, do not generate anything.
    if not uniforms:
        return ""

    result = f"# uniforms for {prefix}\n"

    result += "\n"

    for name, entry in uniforms.items():

        if name == "$compute":
            continue

        func = entry["func"]
        if func not in uniform_types.keys():
            raise ValueError("Error: unknown uniform type for function: " + func)
        uniform_type = uniform_types[func]

        result += f"# {name}\n"
        result += f"BUFFER {prefix}_{name} DATA_TYPE {uniform_type} DATA\n"
        for arg in entry["args"]:
            result += f" {arg}"
        result += "\n"
        result += "END\n"

    return result