from typing import Any, Sequence

from lib.archive import *


def decode(
    reader: FArchiveReader, type_name: str, size: int, path: str
) -> dict[str, Any]:
    if type_name != "ArrayProperty":
        raise Exception(f"Expected ArrayProperty, got {type_name}")
    value = reader.property(type_name, size, path, allow_custom=False)
    data_bytes = value["value"]["values"]
    value["value"] = decode_bytes(data_bytes)
    return value


def connect_info_item_reader(reader: FArchiveReader) -> dict[str, Any]:
    return {
        "connect_to_model_instance_id": reader.guid(),
        "index": reader.byte(),
    }


def connect_info_item_writer(writer: FArchiveWriter, properties: dict[str, Any]):
    writer.guid(properties["connect_to_model_instance_id"])
    writer.byte(properties["index"])


def decode_bytes(c_bytes: Sequence[int]) -> dict[str, Any]:
    if len(c_bytes) == 0:
        return None
    reader = FArchiveReader(bytes(c_bytes))
    data = {}
    data["supported_level"] = reader.i32()
    data["connect"] = {
        "index": reader.byte(),
        "any_place": reader.tarray(connect_info_item_reader),
    }
    # We are guessing here, we don't have information about the type without mapping object names -> types
    # Stairs have 2 connectors (up and down),
    # Roofs have 4 connectors (front, back, right, left)
    if not reader.eof():
        data["other_connectors"] = []
        while not reader.eof():
            data["other_connectors"].append(
                {
                    "index": reader.byte(),
                    "connect": reader.tarray(connect_info_item_reader),
                }
            )
        if len(data["other_connectors"]) not in [2, 4]:
            print(
                f"Warning: unknown connector type with {len(data['other_connectors'])} connectors"
            )
    return data


def encode(
    writer: FArchiveWriter, property_type: str, properties: dict[str, Any]
) -> int:
    if property_type != "ArrayProperty":
        raise Exception(f"Expected ArrayProperty, got {property_type}")
    del properties["custom_type"]
    encoded_bytes = encode_bytes(properties["value"])
    properties["value"] = {"values": [b for b in encoded_bytes]}
    return writer.property_inner(property_type, properties)


def encode_bytes(p: dict[str, Any]) -> bytes:
    if p is None:
        return bytes()
    writer = FArchiveWriter()
    writer.i32(p["supported_level"])
    writer.byte(p["connect"]["index"])
    writer.tarray(connect_info_item_writer, p["connect"]["any_place"])
    if "other_connectors" in p:
        for other in p["other_connectors"]:
            writer.byte(other["index"])
            writer.tarray(connect_info_item_writer, other["connect"])
    encoded_bytes = writer.bytes()
    return encoded_bytes
