/**
 * Minimal ZIP+CSV parser for Harness dashboard data downloads.
 * Parses a ZIP ArrayBuffer containing CSV files into structured JSON tables.
 * No external dependencies — uses only built-in Node.js APIs.
 *
 * Uses the Central Directory (at end of ZIP) for reliable size info,
 * handling ZIPs that use data descriptors (bit 3 flag).
 */
import { inflateRawSync } from "node:zlib";
function readUint16LE(buf, offset) {
    return buf[offset] | (buf[offset + 1] << 8);
}
function readUint32LE(buf, offset) {
    return (buf[offset] | (buf[offset + 1] << 8) | (buf[offset + 2] << 16) | (buf[offset + 3] << 24)) >>> 0;
}
function findCentralDirectory(buf) {
    // Find End of Central Directory record (scan backwards for signature 0x06054b50)
    let eocdOffset = -1;
    for (let i = buf.length - 22; i >= Math.max(0, buf.length - 65557); i--) {
        if (readUint32LE(buf, i) === 0x06054b50) {
            eocdOffset = i;
            break;
        }
    }
    if (eocdOffset < 0)
        return [];
    const cdOffset = readUint32LE(buf, eocdOffset + 16);
    const cdEntries = readUint16LE(buf, eocdOffset + 10);
    const entries = [];
    let pos = cdOffset;
    for (let i = 0; i < cdEntries && pos < eocdOffset; i++) {
        if (readUint32LE(buf, pos) !== 0x02014b50)
            break; // Central directory file header signature
        const compressionMethod = readUint16LE(buf, pos + 10);
        const compressedSize = readUint32LE(buf, pos + 20);
        const uncompressedSize = readUint32LE(buf, pos + 24);
        const filenameLen = readUint16LE(buf, pos + 28);
        const extraLen = readUint16LE(buf, pos + 30);
        const commentLen = readUint16LE(buf, pos + 32);
        const localHeaderOffset = readUint32LE(buf, pos + 42);
        const filename = buf.subarray(pos + 46, pos + 46 + filenameLen).toString("utf-8");
        entries.push({ filename, compressionMethod, compressedSize, uncompressedSize, localHeaderOffset });
        pos += 46 + filenameLen + extraLen + commentLen;
    }
    return entries;
}
function extractFileData(buf, entry) {
    const offset = entry.localHeaderOffset;
    if (readUint32LE(buf, offset) !== 0x04034b50) {
        throw new Error(`Invalid local file header at offset ${offset}`);
    }
    const filenameLen = readUint16LE(buf, offset + 26);
    const extraLen = readUint16LE(buf, offset + 28);
    const dataStart = offset + 30 + filenameLen + extraLen;
    const rawData = buf.subarray(dataStart, dataStart + entry.compressedSize);
    if (entry.compressionMethod === 0) {
        return Buffer.from(rawData);
    }
    else if (entry.compressionMethod === 8) {
        const maxOutput = entry.uncompressedSize || 100 * 1024 * 1024; // 100 MB ceiling
        return inflateRawSync(rawData, { maxOutputLength: maxOutput });
    }
    throw new Error(`Unsupported compression method: ${entry.compressionMethod}`);
}
function parseCSV(text) {
    const lines = text.split(/\r?\n/).filter(l => l.trim());
    if (lines.length < 2)
        return [];
    const headers = lines[0].split(",").map(h => h.trim().replace(/^"|"$/g, ""));
    const rows = [];
    for (let i = 1; i < lines.length; i++) {
        const values = lines[i].split(",").map(v => v.trim().replace(/^"|"$/g, ""));
        const row = {};
        for (let j = 0; j < headers.length; j++) {
            row[headers[j]] = values[j] ?? "";
        }
        rows.push(row);
    }
    return rows;
}
/**
 * Parse a ZIP ArrayBuffer containing CSV files into a structured object.
 * Returns `{ tables: { "TableName": [ {col: val, ...}, ... ], ... } }`.
 */
export function parseZipCsv(buffer) {
    const buf = Buffer.from(buffer);
    const entries = findCentralDirectory(buf);
    const tables = {};
    for (const entry of entries) {
        if (!entry.filename.endsWith(".csv") || entry.filename.endsWith("/"))
            continue;
        if (entry.uncompressedSize === 0)
            continue;
        const data = extractFileData(buf, entry);
        const tableName = entry.filename.replace(/\.csv$/, "");
        tables[tableName] = parseCSV(data.toString("utf-8"));
    }
    return { tables };
}
//# sourceMappingURL=zip-csv.js.map