// This Source Code Form is subject to the terms of the Mozilla Public
// License, v2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/
import * as Comlink from "comlink";
import { deserializeImgDetectionsCustom } from "./deserialization/detections/custom.js";
import { deserializeImgDetections, } from "./deserialization/detections/detection.js";
import { deserializePointCloudData } from "./deserialization/pointcloud/point-cloud.js";
import { deserializeColorFrame } from "./deserialization/video/color.js";
import { deserializeDepthFrameToPointCloud } from "./deserialization/video/depth-to-pointcloud.js";
import { deserializeDepthFrame } from "./deserialization/video/depth.js";
import { deserializeEncodedFrameH264 } from "./deserialization/video/h264.js";
import { deserializeEncodedFrameH265 } from "./deserialization/video/h265.js";
import { deserializeMJPEGFrame } from "./deserialization/video/mjpeg.js";
import { protobufsBySchema } from "./protobuf";
import { parseMessage } from "./utils.js";
import { Profile } from "../protobuf.generated/EncodedFrame.js";
import { Type } from "../protobuf.generated/ImgFrame.js";
import { isCapableOfEncodedStream } from "../utils/encoding";
import { EncodedStreamNotSupportedError, NotInSecureContextError, UnsupportedTopicError, } from "../utils/error";
import { Logger } from "../utils/logger";
import { deserializeRGBDFrameToPointCloud } from "./deserialization/video/rgbd-to-pointcloud.js";
const logger = Logger.getLogger();
export function errorInstanceToErrorCode(error) {
    if (error instanceof UnsupportedTopicError) {
        return "UnsupportedTopic";
    }
    if (error instanceof NotInSecureContextError) {
        return "NotInSecureContext";
    }
    if (error instanceof EncodedStreamNotSupportedError) {
        return "EncodedStreamNotSupported";
    }
    return "DecoderError";
}
const topicDecoders = new Map();
const topicSizes = new Map();
let callback;
function initCallback(cb) {
    callback = cb;
}
function ensureEncodedStreamSupport(topic) {
    if (!globalThis.isSecureContext) {
        throw new NotInSecureContextError(topic);
    }
    if (!isCapableOfEncodedStream()) {
        throw new EncodedStreamNotSupportedError(topic);
    }
}
function handleMessageToDecode({ schema, buffer, topic, neuralCameraIntrinsics, stereoDepthMaxValue, }, configStore, errorCallback) {
    const handleDecodingError = (error) => {
        // TODO: Enable this log once we fix topic unsubscription not working
        // logger.error("An error occurred during DAI message decoding.", error);
        // Type information about an error gets lost during transfer from worker to main thread
        // This means that we have to remap the errors based on type here to an 'error enum'
        // Which can then be parsed on the main thread
        errorCallback?.(errorInstanceToErrorCode(error), topic, {
            message: error.message,
        });
    };
    const protobufSchema = protobufsBySchema[schema];
    if (!protobufSchema) {
        logger.warn(`Unsupported message schema "${schema}"`);
        handleDecodingError(new UnsupportedTopicError(topic, `Unsupported message schema "${schema}"`));
        return;
    }
    const bufferArray = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
    try {
        const message = protobufSchema.decoder.decode(bufferArray);
        if (configStore.connectionConfigValue.debugLogs) {
            logger.debug(`[DepthAI Deserialization] Received message of type ${protobufSchema.type} on topic ${topic}`, { message });
        }
        // Handle the promise correctly
        deserializeDepthAiMessage({
            topic,
            topicSizes,
            topicDecoders,
            neuralCameraIntrinsics,
            message,
            callback,
            type: protobufSchema.type,
            maxSteroDepth: stereoDepthMaxValue,
            onError: handleDecodingError,
        }).catch(handleDecodingError);
    }
    catch (error) {
        handleDecodingError(error);
    }
}
async function deserializeDepthAiMessage(args) {
    const { topicDecoders, topicSizes, type, message, callback, topic, neuralCameraIntrinsics, maxSteroDepth, onError, } = args;
    switch (type) {
        case "encodedFrame": {
            ensureEncodedStreamSupport(topic);
            topicSizes.set(topic, { width: message.width, height: message.height });
            if (message.profile === Profile.AVC) {
                await deserializeEncodedFrameH264({ topic, message, topicDecoders, callback, onError });
            }
            else if (message.profile === Profile.JPEG) {
                await deserializeMJPEGFrame({ topic, message, callback });
            }
            else if (message.profile === Profile.HEVC) {
                await deserializeEncodedFrameH265({ topic, message, topicDecoders, callback, onError });
            }
            else {
                // TODO: Handle UNRECOGNIZED
            }
            break;
        }
        case "imageFrame": {
            const { width, height, type: messageType } = parseMessage(message);
            topicSizes.set(topic, { width, height });
            switch (messageType) {
                case Type.BITSTREAM: {
                    ensureEncodedStreamSupport(topic);
                    await deserializeEncodedFrameH264({ topic, message, topicDecoders, callback, onError });
                    break;
                }
                case Type.RAW16: {
                    deserializeDepthFrameToPointCloud({ topic, message, callback });
                    void deserializeDepthFrame({
                        topic,
                        message,
                        callback,
                        maxStereoDepth: maxSteroDepth / 1000,
                    });
                    break;
                }
                default: {
                    deserializeColorFrame({ topic, message, callback });
                }
            }
            break;
        }
        case "imageDetections": {
            deserializeImgDetections({ topic, message, callback, topicSizes });
            break;
        }
        case "imageDetectionsCustom": {
            deserializeImgDetectionsCustom({ topic, message, callback, topicSizes });
            break;
        }
        case "imageDetectionsSpatial": {
            // TODO: Use separate 3D detection deserializer
            deserializeImgDetections({
                topic,
                topicSizes,
                message: {
                    ...message,
                    detections: message.detections.map((detections) => detections.detection),
                },
                callback,
            });
            break;
        }
        case "pointCloud": {
            deserializePointCloudData({ topic, message, callback });
            break;
        }
        case "imu": {
            const { receiveTime } = parseMessage(message);
            callback({
                topic,
                schemaName: "foxglove.IMU",
                message: message.packets,
                sizeInBytes: message.packets.length * 16, //FIXME: This is made up. But is that a issue?
                receiveTime,
                publishTime: message.tsDevice ?? receiveTime,
            });
            break;
        }
        case 'rgbd': {
            void deserializeRGBDFrameToPointCloud({
                topic,
                topicDecoders,
                cameraIntrinsics: neuralCameraIntrinsics,
                maxStereoDepth: maxSteroDepth,
                message,
                callback,
                onError,
            });
            break;
        }
        default: {
            logger.warn(`Message decoding failed: unsupported type "${type}"`);
            throw new UnsupportedTopicError(topic, `Unsupported message type "${type}"`);
        }
    }
}
// Expose the updated API
Comlink.expose({ initCallback, handleMessageToDecode });
//# sourceMappingURL=deserialization.worker.js.map