/*
 * Copyright (c) 2026, Alliance for Open Media. All rights reserved
 *
 * This source code is subject to the terms of the BSD 3-Clause Clear License
 * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear
 * License was not distributed with this source code in the LICENSE file, you
 * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/.  If the
 * Alliance for Open Media Patent License 1.0 was not distributed with this
 * source code in the PATENTS file, you can obtain it at
 * aomedia.org/license/patent-license/.
 */

#include <cstring>

#include "third_party/googletest/src/googletest/include/gtest/gtest.h"

#include "av2/encoder/atlas_syntax.h"
#include "av2/decoder/decoder.h"
#include "av2/decoder/decodeframe.h"
#include "avm_dsp/bitwriter_buffer.h"
#include "avm_dsp/bitreader_buffer.h"
#include "avm_mem/avm_mem.h"

namespace {

static void rb_error_handler(void *data, avm_codec_err_t error,
                             const char *detail) {
  (void)data;
  (void)error;
  (void)detail;
}

// Write an Atlas OBU: body + extension_flag(0) + trailing bits.
static uint32_t write_atlas_obu(struct AtlasSegmentInfo *atlas, uint8_t *dst) {
  struct avm_write_bit_buffer wb = { dst, 0 };
  av2_write_atlas_segment_info(atlas, &wb);
  avm_wb_write_bit(&wb, 0);  // ats_extension_present_flag
  avm_wb_write_bit(&wb, 1);  // trailing stop bit
  int pad = (8 - wb.bit_offset % 8) % 8;
  if (pad > 0) avm_wb_write_literal(&wb, 0, pad);
  return avm_wb_bytes_written(&wb);
}

class AtlasTest : public ::testing::Test {
 protected:
  void SetUp() override {
    pbi_ = static_cast<AV2Decoder *>(avm_memalign(32, sizeof(AV2Decoder)));
    ASSERT_NE(pbi_, nullptr);
    memset(pbi_, 0, sizeof(*pbi_));
    memset(buf_, 0, sizeof(buf_));
  }
  void TearDown() override { avm_free(pbi_); }

  AV2Decoder *pbi_;
  uint8_t buf_[4096];
};

TEST_F(AtlasTest, SingleAtlasRoundtrip) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = SINGLE_ATLAS;
  src.ats_nominal_width_minus1 = 1919;
  src.ats_nominal_height_minus1 = 1079;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  const int xlayer_id = 0;
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
  ASSERT_EQ(read, written);

  const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
  ASSERT_TRUE(dst->valid);
  EXPECT_EQ(dst->atlas_segment_id, 1);
  EXPECT_EQ(dst->atlas_segment_mode_idc, SINGLE_ATLAS);
  EXPECT_EQ(dst->ats_nominal_width_minus1, 1919);
  EXPECT_EQ(dst->ats_nominal_height_minus1, 1079);
}

TEST_F(AtlasTest, MultistreamAtlasRoundtrip) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 2;
  src.atlas_segment_mode_idc = MULTISTREAM_ATLAS;

  AtlasBasicInfo basic;
  memset(&basic, 0, sizeof(basic));
  basic.ats_atlas_width = 3840;
  basic.ats_atlas_height = 2160;
  basic.ats_num_atlas_segments_minus_1 = 1;  // 2 segments
  basic.ats_background_info_present_flag = 1;
  basic.ats_background_red_value = 128;
  basic.ats_background_green_value = 64;
  basic.ats_background_blue_value = 32;
  basic.ats_input_stream_id[0] = 0;
  basic.ats_segment_top_left_pos_x[0] = 0;
  basic.ats_segment_top_left_pos_y[0] = 0;
  basic.ats_segment_width[0] = 1920;
  basic.ats_segment_height[0] = 2160;
  basic.ats_input_stream_id[1] = 1;
  basic.ats_segment_top_left_pos_x[1] = 1920;
  basic.ats_segment_top_left_pos_y[1] = 0;
  basic.ats_segment_width[1] = 1920;
  basic.ats_segment_height[1] = 2160;

  src.ats_basic_info = &basic;
  src.ats_basic_info_s = basic;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  const int xlayer_id = 0;
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
  ASSERT_EQ(read, written);

  const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
  ASSERT_TRUE(dst->valid);
  EXPECT_EQ(dst->atlas_segment_id, 2);
  EXPECT_EQ(dst->atlas_segment_mode_idc, MULTISTREAM_ATLAS);

  const AtlasBasicInfo *db = dst->ats_basic_info;
  ASSERT_NE(db, nullptr);
  EXPECT_EQ(db->ats_atlas_width, 3840);
  EXPECT_EQ(db->ats_atlas_height, 2160);
  EXPECT_EQ(db->ats_num_atlas_segments_minus_1, 1);
  EXPECT_EQ(db->ats_background_info_present_flag, 1);
  EXPECT_EQ(db->ats_background_red_value, 128);
  EXPECT_EQ(db->ats_background_green_value, 64);
  EXPECT_EQ(db->ats_background_blue_value, 32);
  EXPECT_EQ(db->ats_input_stream_id[0], 0);
  EXPECT_EQ(db->ats_segment_width[0], 1920);
  EXPECT_EQ(db->ats_input_stream_id[1], 1);
  EXPECT_EQ(db->ats_segment_top_left_pos_x[1], 1920);
  EXPECT_EQ(db->ats_segment_width[1], 1920);
}

TEST_F(AtlasTest, MultistreamAlphaAtlasRoundtrip) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 3;
  src.atlas_segment_mode_idc = MULTISTREAM_ALPHA_ATLAS;

  AtlasBasicInfo basic;
  memset(&basic, 0, sizeof(basic));
  basic.ats_atlas_width = 1920;
  basic.ats_atlas_height = 1080;
  basic.ats_num_atlas_segments_minus_1 = 1;  // 2 segments
  basic.ats_alpha_segments_present_flag = 1;
  basic.ats_input_stream_id[0] = 0;
  basic.ats_segment_width[0] = 1920;
  basic.ats_segment_height[0] = 1080;
  basic.ats_alpha_segment_flag[0] = 1;
  basic.ats_input_stream_id[1] = 1;
  basic.ats_segment_width[1] = 1920;
  basic.ats_segment_height[1] = 1080;

  src.ats_basic_info = &basic;
  src.ats_basic_info_s = basic;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  const int xlayer_id = 0;
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
  ASSERT_EQ(read, written);

  const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
  ASSERT_TRUE(dst->valid);
  EXPECT_EQ(dst->atlas_segment_mode_idc, MULTISTREAM_ALPHA_ATLAS);
  EXPECT_EQ(dst->ats_basic_info->ats_alpha_segments_present_flag, 1);
  EXPECT_EQ(dst->ats_basic_info->ats_alpha_segment_flag[0], 1);
}

TEST_F(AtlasTest, BasicAtlasRoundtrip) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = BASIC_ATLAS;

  AtlasBasicInfo basic;
  memset(&basic, 0, sizeof(basic));
  basic.ats_stream_id_present = 1;
  basic.ats_atlas_width = 1920;
  basic.ats_atlas_height = 1080;
  basic.ats_num_atlas_segments_minus_1 = 0;  // 1 segment
  basic.ats_input_stream_id[0] = 0;
  basic.ats_segment_top_left_pos_x[0] = 0;
  basic.ats_segment_top_left_pos_y[0] = 0;
  basic.ats_segment_width[0] = 1920;
  basic.ats_segment_height[0] = 1080;

  src.ats_basic_info = &basic;
  src.ats_basic_info_s = basic;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  const int xlayer_id = 0;
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
  ASSERT_EQ(read, written);

  const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
  ASSERT_TRUE(dst->valid);
  EXPECT_EQ(dst->atlas_segment_mode_idc, BASIC_ATLAS);
  EXPECT_EQ(dst->ats_basic_info->ats_stream_id_present, 1);
  EXPECT_EQ(dst->ats_basic_info->ats_atlas_width, 1920);
  EXPECT_EQ(dst->ats_basic_info->ats_atlas_height, 1080);
  EXPECT_EQ(dst->ats_basic_info->ats_segment_width[0], 1920);
  EXPECT_EQ(dst->ats_basic_info->ats_segment_height[0], 1080);
}

TEST_F(AtlasTest, LabelSegmentInfoRoundtrip) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = SINGLE_ATLAS;
  src.ats_nominal_width_minus1 = 255;
  src.ats_nominal_height_minus1 = 255;
  src.ats_label_seg.ats_signalled_atlas_segment_ids_flag = 1;
  src.ats_label_seg.ats_atlas_segment_id[0] = 42;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  const int xlayer_id = 0;
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, xlayer_id, &rb);
  ASSERT_EQ(read, written);

  const AtlasSegmentInfo *dst = &pbi_->atlas_list[xlayer_id][0];
  EXPECT_EQ(dst->ats_label_seg.ats_signalled_atlas_segment_ids_flag, 1);
  EXPECT_EQ(dst->ats_label_seg.ats_atlas_segment_id[0], 42);
}

TEST_F(AtlasTest, EnhancedAtlasUniformRoundtrip) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = ENHANCED_ATLAS;

  // 2x2 uniform region grid, each region 960x540
  src.ats_reg_params.ats_num_region_columns_minus_1 = 1;
  src.ats_reg_params.ats_num_region_rows_minus_1 = 1;
  src.ats_reg_params.ats_uniform_spacing_flag = 1;
  src.ats_reg_params.ats_region_width_minus_1 = 959;
  src.ats_reg_params.ats_region_height_minus_1 = 539;
  src.ats_reg_params.NumRegionsInAtlas = 4;

  // Single region per segment → 4 segments
  src.ats_reg_seg_map.ats_single_region_per_atlas_segment_flag = 1;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
  ASSERT_EQ(read, written);

  const AtlasSegmentInfo *dst = &pbi_->atlas_list[0][0];
  ASSERT_TRUE(dst->valid);
  EXPECT_EQ(dst->atlas_segment_mode_idc, ENHANCED_ATLAS);
  EXPECT_EQ(dst->ats_reg_params.ats_uniform_spacing_flag, 1);
  EXPECT_EQ(dst->ats_reg_params.ats_region_width_minus_1, 959);
  EXPECT_EQ(dst->ats_reg_params.ats_region_height_minus_1, 539);
  EXPECT_EQ(dst->ats_reg_params.NumRegionsInAtlas, 4);
  EXPECT_EQ(dst->ats_reg_seg_map.ats_single_region_per_atlas_segment_flag, 1);
  EXPECT_EQ(dst->ats_reg_seg_map.ats_num_atlas_segments_minus_1, 3);
}

TEST_F(AtlasTest, EnhancedAtlasNonUniformRoundtrip) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = ENHANCED_ATLAS;

  // 2 columns, 1 row, non-uniform: col widths 640 and 1280
  src.ats_reg_params.ats_num_region_columns_minus_1 = 1;
  src.ats_reg_params.ats_num_region_rows_minus_1 = 0;
  src.ats_reg_params.ats_uniform_spacing_flag = 0;
  src.ats_reg_params.ats_column_width_minus_1[0] = 639;
  src.ats_reg_params.ats_column_width_minus_1[1] = 1279;
  src.ats_reg_params.ats_row_height_minus_1[0] = 1079;
  src.ats_reg_params.NumRegionsInAtlas = 2;

  // Multi-region mapping: 1 segment spanning both regions
  src.ats_reg_seg_map.ats_single_region_per_atlas_segment_flag = 0;
  src.ats_reg_seg_map.ats_num_atlas_segments_minus_1 = 0;
  src.ats_reg_seg_map.ats_top_left_region_column[0] = 0;
  src.ats_reg_seg_map.ats_top_left_region_row[0] = 0;
  src.ats_reg_seg_map.ats_bottom_right_region_column_offset[0] = 1;
  src.ats_reg_seg_map.ats_bottom_right_region_row_offset[0] = 0;
  // Derived values required by encoder assert
  src.ats_reg_seg_map.ats_bottom_right_region_column[0] = 0 + 1;
  src.ats_reg_seg_map.ats_bottom_right_region_row[0] = 0 + 0;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
  ASSERT_EQ(read, written);

  const AtlasSegmentInfo *dst = &pbi_->atlas_list[0][0];
  ASSERT_TRUE(dst->valid);
  EXPECT_EQ(dst->ats_reg_params.ats_uniform_spacing_flag, 0);
  EXPECT_EQ(dst->ats_reg_params.ats_column_width_minus_1[0], 639);
  EXPECT_EQ(dst->ats_reg_params.ats_column_width_minus_1[1], 1279);
  EXPECT_EQ(dst->ats_reg_params.ats_row_height_minus_1[0], 1079);
  EXPECT_EQ(dst->ats_reg_seg_map.ats_single_region_per_atlas_segment_flag, 0);
  EXPECT_EQ(dst->ats_reg_seg_map.ats_bottom_right_region_column[0], 1);
  EXPECT_EQ(dst->ats_reg_seg_map.ats_bottom_right_region_row[0], 0);
}

TEST_F(AtlasTest, MultipleAtlasObus) {
  // Write first Atlas OBU (segment_id = 1)
  AtlasSegmentInfo src1;
  memset(&src1, 0, sizeof(src1));
  src1.valid = 1;
  src1.atlas_segment_id = 1;
  src1.atlas_segment_mode_idc = SINGLE_ATLAS;
  src1.ats_nominal_width_minus1 = 1919;
  src1.ats_nominal_height_minus1 = 1079;

  uint32_t w1 = write_atlas_obu(&src1, buf_);
  ASSERT_GT(w1, 0u);

  // Write second Atlas OBU (segment_id = 2) after the first
  AtlasSegmentInfo src2;
  memset(&src2, 0, sizeof(src2));
  src2.valid = 1;
  src2.atlas_segment_id = 2;
  src2.atlas_segment_mode_idc = SINGLE_ATLAS;
  src2.ats_nominal_width_minus1 = 639;
  src2.ats_nominal_height_minus1 = 479;

  uint32_t w2 = write_atlas_obu(&src2, buf_ + w1);
  ASSERT_GT(w2, 0u);

  // Read first
  struct avm_read_bit_buffer rb1 = { buf_, buf_ + w1, 0, nullptr,
                                     rb_error_handler };
  uint32_t r1 = av2_read_atlas_segment_info_obu(pbi_, 0, &rb1);
  ASSERT_EQ(r1, w1);

  // Read second
  struct avm_read_bit_buffer rb2 = { buf_ + w1, buf_ + w1 + w2, 0, nullptr,
                                     rb_error_handler };
  uint32_t r2 = av2_read_atlas_segment_info_obu(pbi_, 0, &rb2);
  ASSERT_EQ(r2, w2);

  EXPECT_EQ(pbi_->atlas_counter[0], 2);
  EXPECT_EQ(pbi_->atlas_list[0][0].atlas_segment_id, 1);
  EXPECT_EQ(pbi_->atlas_list[0][0].ats_nominal_width_minus1, 1919);
  EXPECT_EQ(pbi_->atlas_list[0][1].atlas_segment_id, 2);
  EXPECT_EQ(pbi_->atlas_list[0][1].ats_nominal_width_minus1, 639);
}

TEST_F(AtlasTest, MultistreamSegmentCountSweep) {
  const int seg_counts[] = { 1, 2, 4 };
  for (int si = 0; si < 3; si++) {
    int n = seg_counts[si];
    AtlasSegmentInfo src;
    memset(&src, 0, sizeof(src));
    src.valid = 1;
    src.atlas_segment_id = 1;
    src.atlas_segment_mode_idc = MULTISTREAM_ATLAS;

    AtlasBasicInfo basic;
    memset(&basic, 0, sizeof(basic));
    basic.ats_atlas_width = 1920 * n;
    basic.ats_atlas_height = 1080;
    basic.ats_num_atlas_segments_minus_1 = n - 1;
    for (int i = 0; i < n; i++) {
      basic.ats_input_stream_id[i] = i;
      basic.ats_segment_top_left_pos_x[i] = 1920 * i;
      basic.ats_segment_width[i] = 1920;
      basic.ats_segment_height[i] = 1080;
    }
    src.ats_basic_info = &basic;
    src.ats_basic_info_s = basic;

    memset(buf_, 0, sizeof(buf_));
    uint32_t written = write_atlas_obu(&src, buf_);
    ASSERT_GT(written, 0u) << "segments=" << n;

    memset(pbi_, 0, sizeof(*pbi_));
    struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                      rb_error_handler };
    uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
    ASSERT_EQ(read, written) << "segments=" << n;

    const AtlasBasicInfo *db = pbi_->atlas_list[0][0].ats_basic_info;
    ASSERT_NE(db, nullptr);
    EXPECT_EQ(db->ats_num_atlas_segments_minus_1, n - 1);
    for (int i = 0; i < n; i++) {
      EXPECT_EQ(db->ats_input_stream_id[i], i);
    }
  }
}

TEST_F(AtlasTest, BasicAtlasNoStreamId) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = BASIC_ATLAS;

  AtlasBasicInfo basic;
  memset(&basic, 0, sizeof(basic));
  basic.ats_stream_id_present = 0;
  basic.ats_atlas_width = 1920;
  basic.ats_atlas_height = 1080;
  basic.ats_num_atlas_segments_minus_1 = 0;
  basic.ats_segment_width[0] = 1920;
  basic.ats_segment_height[0] = 1080;
  src.ats_basic_info = &basic;
  src.ats_basic_info_s = basic;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
  ASSERT_EQ(read, written);
  EXPECT_EQ(pbi_->atlas_list[0][0].ats_basic_info->ats_stream_id_present, 0);
}

TEST_F(AtlasTest, MultistreamNoBackground) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = MULTISTREAM_ATLAS;

  AtlasBasicInfo basic;
  memset(&basic, 0, sizeof(basic));
  basic.ats_atlas_width = 1920;
  basic.ats_atlas_height = 1080;
  basic.ats_num_atlas_segments_minus_1 = 0;
  basic.ats_background_info_present_flag = 0;
  basic.ats_input_stream_id[0] = 0;
  basic.ats_segment_width[0] = 1920;
  basic.ats_segment_height[0] = 1080;
  src.ats_basic_info = &basic;
  src.ats_basic_info_s = basic;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
  ASSERT_EQ(read, written);
  EXPECT_EQ(
      pbi_->atlas_list[0][0].ats_basic_info->ats_background_info_present_flag,
      0);
}

TEST_F(AtlasTest, MultistreamAlphaNoAlpha) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = MULTISTREAM_ALPHA_ATLAS;

  AtlasBasicInfo basic;
  memset(&basic, 0, sizeof(basic));
  basic.ats_atlas_width = 1920;
  basic.ats_atlas_height = 1080;
  basic.ats_num_atlas_segments_minus_1 = 0;
  basic.ats_alpha_segments_present_flag = 0;
  basic.ats_input_stream_id[0] = 0;
  basic.ats_segment_width[0] = 1920;
  basic.ats_segment_height[0] = 1080;
  src.ats_basic_info = &basic;
  src.ats_basic_info_s = basic;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
  ASSERT_EQ(read, written);
  EXPECT_EQ(
      pbi_->atlas_list[0][0].ats_basic_info->ats_alpha_segments_present_flag,
      0);
}

TEST_F(AtlasTest, MultistreamAlphaWithBackground) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = MULTISTREAM_ALPHA_ATLAS;

  AtlasBasicInfo basic;
  memset(&basic, 0, sizeof(basic));
  basic.ats_atlas_width = 1920;
  basic.ats_atlas_height = 1080;
  basic.ats_num_atlas_segments_minus_1 = 0;
  basic.ats_alpha_segments_present_flag = 0;
  basic.ats_background_info_present_flag = 1;
  basic.ats_background_red_value = 255;
  basic.ats_background_green_value = 128;
  basic.ats_background_blue_value = 0;
  basic.ats_input_stream_id[0] = 0;
  basic.ats_segment_width[0] = 1920;
  basic.ats_segment_height[0] = 1080;
  src.ats_basic_info = &basic;
  src.ats_basic_info_s = basic;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
  ASSERT_EQ(read, written);

  const AtlasBasicInfo *db = pbi_->atlas_list[0][0].ats_basic_info;
  EXPECT_EQ(db->ats_background_info_present_flag, 1);
  EXPECT_EQ(db->ats_background_red_value, 255);
  EXPECT_EQ(db->ats_background_green_value, 128);
  EXPECT_EQ(db->ats_background_blue_value, 0);
}

// Covers num_region_rows >= 3 branch.
TEST_F(AtlasTest, EnhancedAtlasThreeRows) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = ENHANCED_ATLAS;

  // 1 column × 3 rows, uniform
  src.ats_reg_params.ats_num_region_columns_minus_1 = 0;
  src.ats_reg_params.ats_num_region_rows_minus_1 = 2;
  src.ats_reg_params.ats_uniform_spacing_flag = 1;
  src.ats_reg_params.ats_region_width_minus_1 = 1919;
  src.ats_reg_params.ats_region_height_minus_1 = 359;
  src.ats_reg_params.NumRegionsInAtlas = 3;

  src.ats_reg_seg_map.ats_single_region_per_atlas_segment_flag = 1;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
  ASSERT_EQ(read, written);

  const AtlasSegmentInfo *dst = &pbi_->atlas_list[0][0];
  EXPECT_EQ(dst->ats_reg_params.ats_num_region_rows_minus_1, 2);
  EXPECT_EQ(dst->ats_reg_params.NumRegionsInAtlas, 3);
  EXPECT_EQ(dst->ats_reg_seg_map.ats_num_atlas_segments_minus_1, 2);
}

TEST_F(AtlasTest, BasicAtlasSegmentCountSweep) {
  const int seg_counts[] = { 2, 4, 8 };
  for (int si = 0; si < 3; si++) {
    int n = seg_counts[si];
    AtlasSegmentInfo src;
    memset(&src, 0, sizeof(src));
    src.valid = 1;
    src.atlas_segment_id = 1;
    src.atlas_segment_mode_idc = BASIC_ATLAS;

    AtlasBasicInfo basic;
    memset(&basic, 0, sizeof(basic));
    basic.ats_stream_id_present = 1;
    basic.ats_atlas_width = 480 * n;
    basic.ats_atlas_height = 270;
    basic.ats_num_atlas_segments_minus_1 = n - 1;
    for (int i = 0; i < n; i++) {
      basic.ats_input_stream_id[i] = i;
      basic.ats_segment_top_left_pos_x[i] = 480 * i;
      basic.ats_segment_width[i] = 480;
      basic.ats_segment_height[i] = 270;
    }
    src.ats_basic_info = &basic;
    src.ats_basic_info_s = basic;

    memset(buf_, 0, sizeof(buf_));
    uint32_t written = write_atlas_obu(&src, buf_);
    ASSERT_GT(written, 0u) << "segments=" << n;

    memset(pbi_, 0, sizeof(*pbi_));
    struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                      rb_error_handler };
    uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
    ASSERT_EQ(read, written) << "segments=" << n;
    EXPECT_EQ(
        pbi_->atlas_list[0][0].ats_basic_info->ats_num_atlas_segments_minus_1,
        n - 1);
  }
}

TEST_F(AtlasTest, DimensionExtremes) {
  const int dims[] = { 0, 1, 65535 };
  for (int di = 0; di < 3; di++) {
    AtlasSegmentInfo src;
    memset(&src, 0, sizeof(src));
    src.valid = 1;
    src.atlas_segment_id = 1;
    src.atlas_segment_mode_idc = SINGLE_ATLAS;
    src.ats_nominal_width_minus1 = dims[di];
    src.ats_nominal_height_minus1 = dims[di];

    memset(buf_, 0, sizeof(buf_));
    uint32_t written = write_atlas_obu(&src, buf_);
    ASSERT_GT(written, 0u) << "dim=" << dims[di];

    memset(pbi_, 0, sizeof(*pbi_));
    struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                      rb_error_handler };
    uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
    ASSERT_EQ(read, written) << "dim=" << dims[di];
    EXPECT_EQ(pbi_->atlas_list[0][0].ats_nominal_width_minus1, dims[di]);
    EXPECT_EQ(pbi_->atlas_list[0][0].ats_nominal_height_minus1, dims[di]);
  }
}

TEST_F(AtlasTest, LabelSegmentIdRange) {
  const int ids[] = { 0, 127, 255 };
  for (int ii = 0; ii < 3; ii++) {
    AtlasSegmentInfo src;
    memset(&src, 0, sizeof(src));
    src.valid = 1;
    src.atlas_segment_id = 1;
    src.atlas_segment_mode_idc = SINGLE_ATLAS;
    src.ats_nominal_width_minus1 = 255;
    src.ats_nominal_height_minus1 = 255;
    src.ats_label_seg.ats_signalled_atlas_segment_ids_flag = 1;
    src.ats_label_seg.ats_atlas_segment_id[0] = ids[ii];

    memset(buf_, 0, sizeof(buf_));
    uint32_t written = write_atlas_obu(&src, buf_);
    ASSERT_GT(written, 0u) << "label_id=" << ids[ii];

    memset(pbi_, 0, sizeof(*pbi_));
    struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                      rb_error_handler };
    uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
    ASSERT_EQ(read, written) << "label_id=" << ids[ii];
    EXPECT_EQ(pbi_->atlas_list[0][0].ats_label_seg.ats_atlas_segment_id[0],
              ids[ii]);
  }
}

TEST_F(AtlasTest, EnhancedAtlas4x4) {
  AtlasSegmentInfo src;
  memset(&src, 0, sizeof(src));
  src.valid = 1;
  src.atlas_segment_id = 1;
  src.atlas_segment_mode_idc = ENHANCED_ATLAS;

  src.ats_reg_params.ats_num_region_columns_minus_1 = 3;
  src.ats_reg_params.ats_num_region_rows_minus_1 = 3;
  src.ats_reg_params.ats_uniform_spacing_flag = 1;
  src.ats_reg_params.ats_region_width_minus_1 = 479;
  src.ats_reg_params.ats_region_height_minus_1 = 269;
  src.ats_reg_params.NumRegionsInAtlas = 16;
  src.ats_reg_seg_map.ats_single_region_per_atlas_segment_flag = 1;

  uint32_t written = write_atlas_obu(&src, buf_);
  ASSERT_GT(written, 0u);

  struct avm_read_bit_buffer rb = { buf_, buf_ + written, 0, nullptr,
                                    rb_error_handler };
  uint32_t read = av2_read_atlas_segment_info_obu(pbi_, 0, &rb);
  ASSERT_EQ(read, written);
  EXPECT_EQ(pbi_->atlas_list[0][0].ats_reg_params.NumRegionsInAtlas, 16);
}

}  // namespace
