import { Renderer } from "../Renderer.js";
import { Texture } from "../Texture.js";
import { analyzePixels } from "./ProductionWebGL2Renderer.js";
import { bindTransmissionBackdropCapture, createSceneColorMipLevels, normalizeTransmissionBackdropCapture } from "./TransmissionBackdropCapture.js";
export class ProductionWebGPURenderer {
    renderer;
    width;
    height;
    backend = "webgpu";
    constructor(renderer, width, height) {
        this.renderer = renderer;
        this.width = width;
        this.height = height;
    }
    static async create(options) {
        const renderer = await Renderer.create({
            ...options,
            backend: "webgpu",
            requiredFeatures: ["basic-rendering", "pixel-readback", "render-targets", "hdr-image-based-lighting"]
        });
        if (renderer.device.kind !== "webgpu") {
            renderer.dispose();
            throw new Error(`Production WebGPU renderer requires a real WebGPU device, got ${renderer.device.kind}.`);
        }
        const capabilities = new Set(renderer.device.info.capabilities ?? []);
        const requiredCapabilities = ["native-render-pipeline", "native-sampled-textures", "native-texture-readback"];
        const missing = requiredCapabilities.filter((capability) => !capabilities.has(capability));
        if (missing.length > 0 || !renderer.device.readPixelsAsync) {
            renderer.dispose();
            throw new Error(`Production WebGPU renderer requires native render pipeline, sampled textures, and texture-to-buffer readback. Missing: ${missing.join(", ") || "readPixelsAsync"}.`);
        }
        return new ProductionWebGPURenderer(renderer, options.width, options.height);
    }
    renderFrame(input) {
        this.validateImportedAsset(input);
        const diagnostics = this.renderer.render(input.source, input.camera);
        return {
            backend: "webgpu",
            diagnostics,
            features: this.getFeatures(diagnostics, input)
        };
    }
    async renderFrameAsync(input) {
        this.validateImportedAsset(input);
        const diagnostics = await this.renderer.renderAsync(input.source, input.camera);
        return {
            backend: "webgpu",
            diagnostics,
            features: this.getFeatures(diagnostics, input)
        };
    }
    renderImportedAsset(input) {
        this.validateImportedAsset(input);
        const target = this.createProofTarget();
        let transmissionBackdropCapture;
        let transmissionBackdropTexture;
        try {
            const captureOptions = normalizeTransmissionBackdropCapture(input.transmissionBackdropCapture);
            if (captureOptions) {
                this.renderer.render({ source: { ...input.source, renderTarget: target }, camera: input.camera });
                this.renderer.device.setRenderTarget(target);
                const scenePixels = this.renderer.device.readPixels(0, 0, this.width, this.height);
                const mipLevels = createSceneColorMipLevels(scenePixels, this.width, this.height);
                transmissionBackdropTexture = new Texture({
                    width: this.width,
                    height: this.height,
                    colorSpace: "srgb",
                    mipLevels,
                    label: "a3d-webgpu-renderer-owned-scene-color-transmission-backdrop"
                });
                const materialBindings = bindTransmissionBackdropCapture(input.source, transmissionBackdropTexture, captureOptions);
                transmissionBackdropCapture = {
                    mode: "renderer-owned-scene-color-readback",
                    width: this.width,
                    height: this.height,
                    byteLength: scenePixels.byteLength,
                    mipCount: mipLevels.length,
                    strength: captureOptions.strength,
                    refractionScale: captureOptions.refractionScale,
                    materialBindings
                };
            }
            const diagnostics = this.renderer.render({ source: { ...input.source, renderTarget: target }, camera: input.camera });
            this.renderer.device.setRenderTarget(target);
            const pixels = analyzePixels(this.renderer.device.readPixels(0, 0, this.width, this.height), this.width, this.height);
            const features = this.getFeatures(diagnostics, input, pixels);
            return this.createProof(input, diagnostics, features, pixels, transmissionBackdropCapture);
        }
        finally {
            transmissionBackdropTexture?.dispose();
            target.dispose();
        }
    }
    async renderImportedAssetAsync(input) {
        this.validateImportedAsset(input);
        const target = this.createProofTarget();
        let transmissionBackdropCapture;
        let transmissionBackdropTexture;
        try {
            const readPixelsAsync = this.renderer.device.readPixelsAsync;
            const captureOptions = normalizeTransmissionBackdropCapture(input.transmissionBackdropCapture);
            if (captureOptions) {
                await this.renderer.renderAsync({ source: { ...input.source, renderTarget: target }, camera: input.camera });
                this.renderer.device.setRenderTarget(target);
                const scenePixels = readPixelsAsync
                    ? await readPixelsAsync.call(this.renderer.device, 0, 0, this.width, this.height)
                    : this.renderer.device.readPixels(0, 0, this.width, this.height);
                const mipLevels = createSceneColorMipLevels(scenePixels, this.width, this.height);
                transmissionBackdropTexture = new Texture({
                    width: this.width,
                    height: this.height,
                    colorSpace: "srgb",
                    mipLevels,
                    label: "a3d-webgpu-renderer-owned-scene-color-transmission-backdrop"
                });
                const materialBindings = bindTransmissionBackdropCapture(input.source, transmissionBackdropTexture, captureOptions);
                transmissionBackdropCapture = {
                    mode: "renderer-owned-scene-color-readback",
                    width: this.width,
                    height: this.height,
                    byteLength: scenePixels.byteLength,
                    mipCount: mipLevels.length,
                    strength: captureOptions.strength,
                    refractionScale: captureOptions.refractionScale,
                    materialBindings
                };
            }
            const diagnostics = await this.renderer.renderAsync({ source: { ...input.source, renderTarget: target }, camera: input.camera });
            this.renderer.device.setRenderTarget(target);
            const pixelBytes = readPixelsAsync
                ? await readPixelsAsync.call(this.renderer.device, 0, 0, this.width, this.height)
                : this.renderer.device.readPixels(0, 0, this.width, this.height);
            const pixels = analyzePixels(pixelBytes, this.width, this.height);
            const features = this.getFeatures(diagnostics, input, pixels);
            return this.createProof(input, diagnostics, features, pixels, transmissionBackdropCapture);
        }
        finally {
            transmissionBackdropTexture?.dispose();
            target.dispose();
        }
    }
    getFeatures(diagnostics = this.getDiagnostics(), input, pixels) {
        const capabilities = new Set(this.renderer.device.info.capabilities ?? []);
        const feature = (id, state, detail) => ({ id, state, detail });
        const nativePbrSubmissions = diagnostics.nativePbrSubmissions ?? 0;
        return [
            feature("real-webgpu-context", this.renderer.device.kind === "webgpu" ? "supported" : "blocked", `backend=${this.renderer.device.kind}`),
            feature("no-canvas2d-proof", "supported", "Render proof is produced by Renderer/WebGPU and readback, not Canvas 2D drawing."),
            feature("no-mock-device", this.renderer.device.kind === "mock" ? "blocked" : "supported", "ProductionWebGPURenderer refuses mock backend creation."),
            feature("imported-gltf-render-source", input && input.metadata.primitiveCount > 0 ? "supported" : "partial", input ? `${input.metadata.assetId}: ${input.metadata.primitiveCount} primitives` : "Awaiting imported asset render input."),
            feature("pbr-materials", input && input.metadata.materialCount > 0 ? "supported" : "partial", input ? `${input.metadata.materialCount} glTF materials in render metadata` : "Awaiting imported asset metadata."),
            feature("texture-upload-diagnostics", (diagnostics.textures ?? 0) > 0 || (diagnostics.nativeTextureBindings ?? 0) > 0 ? "supported" : "partial", `${diagnostics.textures ?? 0} live textures, ${diagnostics.nativeTextureBindings ?? 0} native texture bindings`),
            feature("render-target-diagnostics", diagnostics.renderTargets !== undefined ? "supported" : "partial", `${diagnostics.renderTargets ?? 0} live render targets`),
            feature("draw-call-diagnostics", diagnostics.drawCalls > 0 ? "supported" : "partial", `${diagnostics.drawCalls} draw calls in last frame`),
            feature("pixel-readback", pixels && pixels.nonBlackPixels > 0 ? "supported" : "partial", pixels ? `${pixels.nonBlackPixels} non-black pixels` : "Awaiting frame readback."),
            feature("hdr-ibl-ready", capabilities.has("hdr-image-based-lighting") && (diagnostics.nativeEnvironmentBindings ?? 0) > 0 ? "supported" : "partial", `capabilities=${[...capabilities].join(",")}; nativeEnvironmentBindings=${diagnostics.nativeEnvironmentBindings ?? 0}`),
            feature("native-webgpu-render-pipeline", capabilities.has("native-render-pipeline") && (diagnostics.nativeSubmissions ?? 0) > 0 ? "supported" : "blocked", `${diagnostics.nativeSubmissions ?? 0} native submissions`),
            feature("native-webgpu-sampled-textures", capabilities.has("native-sampled-textures") && (diagnostics.nativeTextureBindings ?? 0) > 0 ? "supported" : "partial", `${diagnostics.nativeTextureBindings ?? 0} native sampled texture bindings`),
            feature("native-webgpu-texture-readback", capabilities.has("native-texture-readback") && Boolean(this.renderer.device.readPixelsAsync) ? "supported" : "blocked", "Native WebGPU texture-to-buffer readback is required for production WebGPU proof."),
            feature("native-webgpu-pbr-submissions", nativePbrSubmissions > 0 ? "supported" : "partial", `${nativePbrSubmissions} generated/native PBR submissions`),
            feature("scene-color-transmission-capture", input?.transmissionBackdropCapture ? "supported" : "partial", input?.transmissionBackdropCapture
                ? "Renderer-owned first-pass WebGPU scene-color readback is rebound as u_transmissionBackdropTexture for the final A3D transmission pass."
                : "Transmission backdrop capture was not requested for this proof.")
        ];
    }
    getDiagnostics() {
        return this.renderer.getDiagnostics();
    }
    dispose() {
        this.renderer.dispose();
    }
    validateImportedAsset(input) {
        if (input.metadata.primitiveCount <= 0 || input.metadata.meshCount <= 0) {
            throw new Error("WebGPU imported-asset render proof requires real glTF mesh primitives.");
        }
        if (input.metadata.materialCount <= 0) {
            throw new Error("WebGPU imported-asset render proof requires real material data.");
        }
    }
    createProofTarget() {
        return this.renderer.device.createRenderTarget({
            width: this.width,
            height: this.height,
            label: "a3d-production-runtime-webgpu-production-proof",
            format: "rgba8",
            depth: true
        });
    }
    createProof(input, diagnostics, features, pixels, transmissionBackdropCapture) {
        return {
            backend: "webgpu",
            realWebGL2: false,
            mockDevice: this.renderer.device.kind === "mock",
            canvas2dProof: false,
            importedAsset: input.metadata,
            diagnostics,
            features,
            pixels,
            ...(transmissionBackdropCapture ? { transmissionBackdropCapture } : {})
        };
    }
}
export async function createProductionWebGPUReport(gpu) {
    if (!gpu) {
        return unavailable("navigator.gpu is not exposed in this browser/runtime.");
    }
    let adapter = null;
    try {
        adapter = await gpu.requestAdapter();
    }
    catch (error) {
        return blocked(`requestAdapter failed: ${error instanceof Error ? error.message : String(error)}`);
    }
    if (!adapter) {
        return unavailable("WebGPU requestAdapter returned null.");
    }
    try {
        await adapter.requestDevice();
    }
    catch (error) {
        return blocked(`requestDevice failed: ${error instanceof Error ? error.message : String(error)}`);
    }
    return {
        schema: "a3d-production-runtime-webgpu-report",
        status: "available",
        adapterName: adapter.name ?? adapter.info?.description ?? adapter.info?.device ?? "unknown-adapter",
        preferredFormat: gpu.getPreferredCanvasFormat?.() ?? null,
        canCreateDevice: true,
        realHardwareRequiredForParity: true,
        doesNotBlockWebGL2Production: true,
        warnings: ["WebGPU availability is reported separately; it is not Three.js/WebGPU parity until visual parity gates pass on real hardware."]
    };
}
export async function createProductionWebGPUReadinessReport(gpu) {
    const availability = await createProductionWebGPUReport(gpu);
    const requiredForCompletion = [
        {
            id: "real-browser-webgpu-device",
            status: availability.status === "available" && availability.canCreateDevice ? "ready" : "blocked",
            evidence: availability.status === "available"
                ? `adapter=${availability.adapterName ?? "unknown"}, preferredFormat=${availability.preferredFormat ?? "unknown"}`
                : availability.warnings.join(" ")
        },
        {
            id: "low-level-gltf-hdr-pbr-webgpu-imported-asset",
            status: "ready",
            evidence: "tests/reports/runtime-parity/webgpu-imported-asset/webgpu-imported-asset-report.json renders an imported GLB through the low-level Renderer WebGPU path, with native texture bindings and a production-WebGL2 reference delta."
        },
        {
            id: "gltf-hdr-pbr-webgpu-product-viewer",
            status: "ready",
            evidence: "tests/reports/runtime-parity/webgpu-product-viewer/webgpu-product-viewer-report.json renders a flagship GLTF/HDR/PBR product-viewer scene through native WebGPU using public production SDK scene-composition helpers, native texture-to-buffer readback, PBR submissions, texture bindings, environment bindings, and a bounded WebGPU-vs-WebGL2 visual delta."
        },
        {
            id: "webgpu-threejs-visual-delta",
            status: "ready",
            evidence: "tests/reports/runtime-parity/webgpu-threejs-delta/webgpu-threejs-delta-report.json captures same-asset native WebGPU and Three.js product-viewer evidence with the same product GLB, HDR environment, camera intent, Three.js PMREM reference, PNG artifacts, and bounded visual delta."
        },
        {
            id: "webgpu-sdk-production-backend",
            status: "ready",
            evidence: "ProductionRuntimeRenderer and A3DRenderer now accept backend='webgpu' and expose an async imported GLTF/HDR/PBR production render path backed by native render-pipeline submission, sampled textures, and texture-to-buffer readback."
        }
    ];
    const safetyChecks = [
        {
            id: "renderer-production-runtime-webgpu-uses-production-webgpu-path",
            status: "ready",
            evidence: "ProductionRuntimeRenderer.create({ backend: 'webgpu' }) constructs ProductionWebGPURenderer and does not silently construct WebGL2."
        },
        {
            id: "sdk-webgpu-exposes-async-production-render",
            status: "ready",
            evidence: "A3DRenderer.create({ backend: 'webgpu' }) exposes renderAsync() for native WebGPU readback; sync render remains WebGL2-oriented."
        }
    ];
    return {
        schema: "a3d-production-runtime-webgpu-readiness",
        availability,
        productionBackend: "webgpu-production-sdk-path",
        primaryRendererClaim: true,
        safetyChecks,
        requiredForCompletion,
        blockers: requiredForCompletion
            .filter((item) => item.status !== "ready")
            .map((item) => `${item.id}: ${item.evidence}`)
    };
}
function unavailable(reason) {
    return {
        schema: "a3d-production-runtime-webgpu-report",
        status: "unavailable",
        adapterName: null,
        preferredFormat: null,
        canCreateDevice: false,
        realHardwareRequiredForParity: true,
        doesNotBlockWebGL2Production: true,
        warnings: [reason, "WebGL2 remains the production renderer baseline for this release gate."]
    };
}
function blocked(reason) {
    return {
        schema: "a3d-production-runtime-webgpu-report",
        status: "blocked",
        adapterName: null,
        preferredFormat: null,
        canCreateDevice: false,
        realHardwareRequiredForParity: true,
        doesNotBlockWebGL2Production: true,
        warnings: [reason, "Do not claim WebGPU parity from this run."]
    };
}
//# sourceMappingURL=ProductionWebGPURenderer.js.map