export class WGSLReflection {

    constructor(wgslSource) {

        this.src = wgslSource;
        this.structs = {};
        this.bindings = [];

        this.parseStructs();
        this.parseBindings();
    }

    //
    // ------------------------------------------------------------
    // STRUCT PARSING
    // ------------------------------------------------------------
    //
    parseStructs() {

        const structRegex =
            /struct\s+(\w+)\s*\{([^}]+)\}/g;

        let match;
        while ((match = structRegex.exec(this.src))) {

            const structName = match[1];
            const body = match[2].trim();

            const fields = this.parseStructFields(body);
            const size = fields.reduce((sum, f) => sum + f.size, 0);

            this.structs[structName] = {
                name: structName,
                fields,
                size
            };
        }
    }

    parseStructFields(body) {

        const lines = body.split("\n");
        const fields = [];

        for (let line of lines) {

            line = line.trim();
            if (!line) continue;

            const m = line.match(/(\w+)\s*:\s*([^;]+);/);
            if (!m) continue;

            const fieldName = m[1];
            const wgslType  = m[2].trim();
            const size = this.computeTypeSize(wgslType);

            fields.push({ fieldName, wgslType, size });
        }

        return fields;
    }


    //
    // ------------------------------------------------------------
    // BINDING PARSING
    // ------------------------------------------------------------
    //
    parseBindings() {

        const varRegex =
        /@group\((\d+)\)\s*@binding\((\d+)\)\s*var<([^>]+)>\s+(\w+)\s*:\s*([^;]+);/g;

        let match;
        while ((match = varRegex.exec(this.src))) {

            const group   = parseInt(match[1]);
            const binding = parseInt(match[2]);
            const type    = match[3].trim();
            const varName = match[4].trim();
            const varType = match[5].trim();

            const size = this.computeTypeSize(varType);

            this.bindings.push({
                group,
                binding,
                type,
                varName,
                varType,
                size
            });
        }
    }


    //
    // ------------------------------------------------------------
    // TYPE SIZE COMPUTATION (Simplified)
    // ------------------------------------------------------------
    //
    computeTypeSize(wgslType) {

        // scalar
        if (wgslType === "f32" || wgslType === "u32" || wgslType === "i32") {
            return 4;
        }

        // array<f32, N>
        const arrMatch = wgslType.match(/array<(\w+),\s*(\d+)>/);
        if (arrMatch) {
            const elementType = arrMatch[1];
            const count = parseInt(arrMatch[2]);
            return this.computeTypeSize(elementType) * count;
        }

        // array<f32> runtime-sized → minimal
        const runtimeArr = wgslType.match(/array<(\w+)>/);
        if (runtimeArr) {
            return 4;
        }

        // struct
        if (this.structs[wgslType]) {
            return this.structs[wgslType].size;
        }

        return 4;
    }


    //
    // ------------------------------------------------------------
    // SUMMARY OUTPUT
    // ------------------------------------------------------------
    //
    reflect() {
        return {
            structs: this.structs,
            bindings: this.bindings
        };
    }
}
