'use client';
// 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/

function uint8ArrayToUint16Array(uint8Array) {
  if (uint8Array.length % 2 !== 0) {
    throw new Error("Uint8Array length must be a multiple of 2 for conversion to Uint16Array");
  }
  const uint16Array = new Uint16Array(uint8Array.length / 2);
  for (let i = 0; i < uint16Array.length; i++) {
    const lowByte = uint8Array[i * 2];
    const highByte = uint8Array[i * 2 + 1];
    // eslint-disable-next-line @foxglove/strict-equality
    if (highByte === undefined || lowByte === undefined) {
      throw new Error("Invalid data in uint8Array");
    }
    uint16Array[i] = highByte << 8 | lowByte;
  }
  return uint16Array;
}

/* H264 (i420) to RGBA */
function i420ToRgbaToPointcloud(i420Data, i420Width, i420Height, depthWidth, depthHeight, data) {
  const frameSize = i420Width * i420Height;
  const uOffset = frameSize;
  const vOffset = frameSize + frameSize / 4;
  const pointCount = data.byteLength / 16;
  const buffer = new ArrayBuffer(data.byteLength);
  const view = new DataView(buffer);
  const dataView = new DataView(data.buffer);
  for (let i = 0; i < pointCount; i++) {
    var _i420Data$index, _i420Data, _i420Data2;
    const depthX = i % depthWidth;
    const depthY = Math.floor(i / depthWidth);
    const i420X = Math.round(depthX * (i420Width / depthWidth));
    const i420Y = Math.round(depthY * (i420Height / depthHeight));
    if (i420X >= i420Width || i420Y >= i420Height) {
      continue;
    }
    const index = i420Y * i420Width + i420X;
    const uvIndex = Math.floor(i420Y / 2) * (i420Width / 2) + Math.floor(i420X / 2);
    const Y = (_i420Data$index = i420Data[index]) !== null && _i420Data$index !== void 0 ? _i420Data$index : 0;
    const U = ((_i420Data = i420Data[uOffset + uvIndex]) !== null && _i420Data !== void 0 ? _i420Data : 128) - 128;
    const V = ((_i420Data2 = i420Data[vOffset + uvIndex]) !== null && _i420Data2 !== void 0 ? _i420Data2 : 128) - 128;
    let R = Y + 1.402 * V;
    let G = Y - 0.344136 * U - 0.714136 * V;
    let B = Y + 1.772 * U;
    R = Math.min(255, Math.max(0, R));
    G = Math.min(255, Math.max(0, G));
    B = Math.min(255, Math.max(0, B));
    const offset = i * 16;
    view.setFloat32(offset, dataView.getFloat32(offset, true), true); // x
    view.setFloat32(offset + 4, dataView.getFloat32(offset + 4, true), true); // y
    view.setFloat32(offset + 8, dataView.getFloat32(offset + 8, true), true); // z
    view.setUint8(offset + 12, R); // Red
    view.setUint8(offset + 13, G); // Green
    view.setUint8(offset + 14, B); // Blue
    view.setUint8(offset + 15, 255); // Alpha (fully opaque)
  }
  return new Uint8Array(buffer);
}

export { i420ToRgbaToPointcloud as i, uint8ArrayToUint16Array as u };
