import { decodeVarintInt32 } from "../../decoding/integerDecodingUtils";
import { columnTypeHasChildren, columnTypeHasName, decodeColumnType } from "./typeMap";
const textDecoder = new TextDecoder();
const SUPPORTED_COLUMN_TYPES = "0-3(ID), 4(GEOMETRY), 10-29(scalars), 30(STRUCT)";
const SUPPORTED_FIELD_TYPES = "10-29(scalars), 30(STRUCT)";
/**
 * Decodes a length-prefixed UTF-8 string.
 * Layout: [len: varint32][bytes: len]
 */
function decodeString(src, offset) {
    const length = decodeVarintInt32(src, offset, 1)[0];
    if (length === 0) {
        return "";
    }
    const start = offset.get();
    const end = start + length;
    const view = src.subarray(start, end);
    offset.add(length);
    return textDecoder.decode(view);
}
/**
 * Converts a Column to a Field.
 * Used when decoding Field metadata which has the same format as Column.
 */
function columnToField(column) {
    return {
        name: column.name,
        nullable: column.nullable,
        scalarField: column.scalarType,
        complexField: column.complexType,
        type: column.type === "scalarType" ? "scalarField" : "complexField",
    };
}
/**
 * Decodes a Field used as part of complex types (STRUCT children).
 */
export function decodeField(src, offset) {
    const typeCode = decodeVarintInt32(src, offset, 1)[0] >>> 0;
    if (typeCode < 10 || typeCode > 30) {
        throw new Error(`Unsupported field type code ${typeCode}. Supported: ${SUPPORTED_FIELD_TYPES}`);
    }
    const column = decodeColumnType(typeCode);
    if (columnTypeHasName(typeCode)) {
        column.name = decodeString(src, offset);
    }
    if (columnTypeHasChildren(typeCode)) {
        const childCount = decodeVarintInt32(src, offset, 1)[0] >>> 0;
        column.complexType.children = new Array(childCount);
        for (let i = 0; i < childCount; i++) {
            column.complexType.children[i] = decodeField(src, offset);
        }
    }
    return columnToField(column);
}
/**
 * The typeCode encodes the column type, nullable flag, and whether it has name/children.
 */
function decodeColumn(src, offset) {
    const typeCode = decodeVarintInt32(src, offset, 1)[0] >>> 0;
    const column = decodeColumnType(typeCode);
    if (!column) {
        throw new Error(`Unsupported column type code ${typeCode}. Supported: ${SUPPORTED_COLUMN_TYPES}`);
    }
    if (columnTypeHasName(typeCode)) {
        column.name = decodeString(src, offset);
    }
    else {
        // ID and GEOMETRY columns have implicit names
        if (typeCode >= 0 && typeCode <= 3) {
            column.name = "id";
        }
        else if (typeCode === 4) {
            column.name = "geometry";
        }
    }
    if (columnTypeHasChildren(typeCode)) {
        // Only STRUCT (typeCode 30) has children
        const childCount = decodeVarintInt32(src, offset, 1)[0] >>> 0;
        const complexCol = column.complexType;
        complexCol.children = new Array(childCount);
        for (let i = 0; i < childCount; i++) {
            complexCol.children[i] = decodeField(src, offset);
        }
    }
    return column;
}
/**
 * Top-level decoder for embedded tileset metadata.
 * Reads exactly ONE FeatureTableSchema from the stream.
 *
 * @param bytes The byte array containing the metadata
 * @param offset The current offset in the byte array (will be advanced)
 */
export function decodeEmbeddedTileSetMetadata(bytes, offset) {
    const meta = {};
    meta.featureTables = [];
    const table = {};
    table.name = decodeString(bytes, offset);
    const extent = decodeVarintInt32(bytes, offset, 1)[0] >>> 0;
    const columnCount = decodeVarintInt32(bytes, offset, 1)[0] >>> 0;
    table.columns = new Array(columnCount);
    for (let j = 0; j < columnCount; j++) {
        table.columns[j] = decodeColumn(bytes, offset);
    }
    meta.featureTables.push(table);
    return [meta, extent];
}
//# sourceMappingURL=embeddedTilesetMetadataDecoder.js.map