#include "glaze/toml.hpp"

#include <chrono>
#include <cstdint>
#include <limits>
#include <map>
#include <set>
#include <span>
#include <string_view>
#include <unordered_set>

#include "ut/ut.hpp"

using namespace ut;

struct my_struct
{
   int i = 287;
   double d = 3.14;
   std::string hello = "Hello World";
   std::array<uint64_t, 3> arr = {1, 2, 3};
};

struct nested
{
   int x = 10;
   std::string y = "test";

   bool operator==(const nested&) const = default;
};

struct simple_container
{
   nested inner{};
   double value = 5.5;
};

struct advanced_container
{
   nested inner{};
   nested inner_two{};
   double value = 5.5;
};

struct level_one
{
   int value{0};
};

struct level_two
{
   level_one l1{};
};

struct dotted_access_struct
{
   level_two l2{};
};

struct dotted_unknown_inner
{
   std::string value{"initial"};
};

struct dotted_unknown_root
{
   dotted_unknown_inner key{};
};

struct simple_value_struct
{
   std::string value{"initial"};
};

template <>
struct glz::meta<dotted_unknown_inner>
{
   using T = dotted_unknown_inner;
   static constexpr auto value = object("value", &T::value);
};

template <>
struct glz::meta<dotted_unknown_root>
{
   using T = dotted_unknown_root;
   static constexpr auto value = object("key", &T::key);
};

template <>
struct glz::meta<simple_value_struct>
{
   using T = simple_value_struct;
   static constexpr auto value = object("value", &T::value);
};

struct optional_struct
{
   std::optional<int> maybe = 99;
};

struct inline_table_member
{
   std::string key1{};
   int key2{};

   bool operator==(const inline_table_member&) const = default;
};

template <>
struct glz::meta<inline_table_member>
{
   using T = inline_table_member;
   static constexpr auto value = object("key1", &T::key1, "key2", &T::key2);
};

struct struct_with_inline_table
{
   std::string name{};
   inline_table_member inline_data{};

   bool operator==(const struct_with_inline_table&) const = default;
};

template <>
struct glz::meta<struct_with_inline_table>
{
   using T = struct_with_inline_table;
   static constexpr auto value = object("name", &T::name, "inline_data", &T::inline_data);
};

struct complex_strings_struct
{
   std::string basic_multiline{};
   std::string literal_multiline{};
   std::string literal_multiline_with_quotes{};

   bool operator==(const complex_strings_struct&) const = default;
};

template <>
struct glz::meta<complex_strings_struct>
{
   using T = complex_strings_struct;
   static constexpr auto value =
      object("basic_multiline", &T::basic_multiline, "literal_multiline", &T::literal_multiline,
             "literal_multiline_with_quotes", &T::literal_multiline_with_quotes);
};

struct comment_test_struct
{
   int a{};
   std::string b{};

   bool operator==(const comment_test_struct&) const = default;
};

template <>
struct glz::meta<comment_test_struct>
{
   using T = comment_test_struct;
   static constexpr auto value = object("a", &T::a, "b", &T::b);
};

struct non_null_term_struct
{
   int value{};
   bool operator==(const non_null_term_struct&) const = default;
};

template <>
struct glz::meta<non_null_term_struct>
{
   using T = non_null_term_struct;
   static constexpr auto value = object("value", &T::value);
};

// ========== Chrono test structures ==========

struct duration_test_struct
{
   std::chrono::seconds seconds_val{};
   std::chrono::milliseconds millis_val{};
   std::chrono::minutes minutes_val{};
   std::chrono::hours hours_val{};

   bool operator==(const duration_test_struct&) const = default;
};

struct system_time_test_struct
{
   std::chrono::system_clock::time_point timestamp{};
   int value{};

   bool operator==(const system_time_test_struct&) const = default;
};

struct chrono_combined_struct
{
   std::string name{};
   std::chrono::seconds timeout{};
   std::chrono::system_clock::time_point created_at{};
   std::chrono::milliseconds latency{};

   bool operator==(const chrono_combined_struct&) const = default;
};

struct local_date_test_struct
{
   std::chrono::year_month_day date{};
   int value{};

   bool operator==(const local_date_test_struct&) const = default;
};

struct local_time_test_struct
{
   std::chrono::hh_mm_ss<std::chrono::seconds> time_sec{std::chrono::seconds{0}};
   std::chrono::hh_mm_ss<std::chrono::milliseconds> time_ms{std::chrono::milliseconds{0}};
};

// ========== Set test structures ==========

struct set_test_struct
{
   std::set<int> int_set{};
   std::set<std::string> string_set{};

   bool operator==(const set_test_struct&) const = default;
};

struct unordered_set_test_struct
{
   std::unordered_set<int> int_uset{};

   bool operator==(const unordered_set_test_struct&) const = default;
};

struct combined_containers_struct
{
   std::vector<int> vec{};
   std::set<int> set{};
   std::array<int, 3> arr{};

   bool operator==(const combined_containers_struct&) const = default;
};

// ========== Enum types for TOML enum serialization tests ==========
enum class Color { Red, Green, Blue };

template <>
struct glz::meta<Color>
{
   using enum Color;
   static constexpr auto value = glz::enumerate(Red, Green, Blue);
};

enum class Status { Pending, Active, Completed, Cancelled };

template <>
struct glz::meta<Status>
{
   using enum Status;
   static constexpr auto value = glz::enumerate(Pending, Active, Completed, Cancelled);
};

// Enum with custom string names
enum class LogLevel { Debug = 0, Info = 1, Warning = 2, Error = 3 };

template <>
struct glz::meta<LogLevel>
{
   using enum LogLevel;
   static constexpr auto value = glz::enumerate("debug", Debug, "info", Info, "warning", Warning, "error", Error);
};

// Raw enum without glz::meta (should serialize as number)
enum class RawEnum { A = 0, B = 1, C = 2 };

// Single-value enum (edge case)
enum class SingleEnum { OnlyValue };

template <>
struct glz::meta<SingleEnum>
{
   using enum SingleEnum;
   static constexpr auto value = glz::enumerate(OnlyValue);
};

// Struct containing enum members
struct config_with_enums
{
   std::string name{};
   Color color{Color::Red};
   Status status{Status::Pending};
   int priority{0};

   bool operator==(const config_with_enums&) const = default;
};

template <>
struct glz::meta<config_with_enums>
{
   using T = config_with_enums;
   static constexpr auto value =
      object("name", &T::name, "color", &T::color, "status", &T::status, "priority", &T::priority);
};

suite starter = [] {
   "example"_test = [] {
      my_struct s{};
      std::string buffer{};
      expect(not glz::write_toml(s, buffer));
      expect(buffer ==
             R"(i = 287
d = 3.14
hello = "Hello World"
arr = [1, 2, 3])");
   };

   "read_basic_struct"_test = [] {
      std::string toml_input = R"(i = 42
d = 2.71
hello = "Test String"
arr = [4, 5, 6])";

      my_struct s{};
      expect(not glz::read_toml(s, toml_input));
      expect(s.i == 42);
      expect(s.d == 2.71);
      expect(s.hello == "Test String");
      expect(s.arr[0] == 4);
      expect(s.arr[1] == 5);
      expect(s.arr[2] == 6);
   };

   "read_integer"_test = [] {
      std::string toml_input = "123";
      int value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 123);
   };

   "read_no_valid_digits_integer"_test = [] {
      // We require at least one valid digit.
      std::string toml_input = "BAD";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_overflow_integer"_test = [] {
      // Max uint64 value plus one.
      std::string toml_input = "18446744073709551616";
      uint64_t value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_nearly_overfow_integer"_test = [] {
      // Max uint64 value.
      std::string toml_input = "18446744073709551615";
      uint64_t value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 18446744073709551615ull);
   };

   "read_wrong_underflow_integer"_test = [] {
      // Min int64 value minus one.
      std::string toml_input = "-9223372036854775809";
      int64_t value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_nearly_underflow_integer"_test = [] {
      // Min int64 value.
      std::string toml_input = "-9223372036854775808";
      int64_t value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == -9223372036854775807ll - 1);
   };

   "read_negative_integer"_test = [] {
      std::string toml_input = "-123";
      int value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == -123);
   };

   "read_wrong_negative_integer"_test = [] {
      std::string toml_input = "-123";
      // Negative values should not succeed for unsigned types.
      unsigned int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_positive_integer"_test = [] {
      std::string toml_input = "+123";
      int value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 123);
   };

   "read_negative_zero_integer"_test = [] {
      std::string toml_input = "-0";
      int value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 0);
   };

   "read_unsigned_negative_zero_integer"_test = [] {
      std::string toml_input = "-0";
      unsigned int value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 0);
   };

   "read_positive_zero_integer"_test = [] {
      std::string toml_input = "+0";
      int value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 0);
   };

   "read_hex_integer"_test = [] {
      std::string toml_input = "0x012abCD";
      int value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 0x012abCD);
   };

   "read_wrong_hex_integer"_test = [] {
      std::string toml_input = "0xG";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_hex_negative_integer"_test = [] {
      std::string toml_input = "-0x12abCD";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_hex_positive_integer"_test = [] {
      std::string toml_input = "+0x12abCD";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_hex_negative_unsigned_integer"_test = [] {
      std::string toml_input = "-0x1";
      unsigned int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_bad_digits_integer"_test = [] {
      std::string toml_input = "123ABC";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_binary_integer"_test = [] {
      std::string toml_input = "0b010";
      int value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 0b010);
   };

   "read_wrong_binary_integer"_test = [] {
      std::string toml_input = "0b3";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_binary_negative_integer"_test = [] {
      std::string toml_input = "-0b10";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_binary_positive_integer"_test = [] {
      std::string toml_input = "+0b10";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_binary_negative_unsigned_integer"_test = [] {
      std::string toml_input = "-0b1";
      unsigned int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_octal_integer"_test = [] {
      std::string toml_input = "0o01267";
      int value{};
      expect(not glz::read_toml(value, toml_input));
      // Leading '0' to specify octal in C++.
      expect(value == 001267);
   };

   "read_wrong_octal_integer"_test = [] {
      std::string toml_input = "0o8";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_octal_negative_integer"_test = [] {
      std::string toml_input = "-0o1267";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_octal_positive_integer"_test = [] {
      std::string toml_input = "+0o1267";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_octal_negative_unsigned_integer"_test = [] {
      std::string toml_input = "-0o7";
      unsigned int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_underscore_integer"_test = [] {
      std::string toml_input = "1_2_3";
      int value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 123);
   };

   "read_wrong_underscore_integer"_test = [] {
      std::string toml_input = "1__2_3";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_leading_underscore_integer"_test = [] {
      std::string toml_input = "_123";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_leading_underscore_negative_integer"_test = [] {
      std::string toml_input = "-_123";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_leading_underscore_positive_integer"_test = [] {
      std::string toml_input = "+_123";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_leading_underscore_hex_integer"_test = [] {
      std::string toml_input = "0x_12abCD";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_leading_underscore_binary_integer"_test = [] {
      std::string toml_input = "0b_10";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_leading_underscore_octal_integer"_test = [] {
      std::string toml_input = "0o_1267";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_trailing_underscore_integer"_test = [] {
      std::string toml_input = "123_";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_leading_zero_integer"_test = [] {
      std::string toml_input = "0123";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_leading_zero_negative_integer"_test = [] {
      std::string toml_input = "-0123";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_wrong_leading_zero_positive_integer"_test = [] {
      std::string toml_input = "+0123";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   // In TOML, integers are not able to have an exponent component.
   "read_wrong_exponent_integer"_test = [] {
      std::string toml_input = "1e2";
      int value{};
      auto error = glz::read_toml(value, toml_input);
      expect(error);
      expect(error == glz::error_code::parse_number_failure);
   };

   "read_decimal_int8_boundaries"_test = [] {
      {
         std::string toml_input = "-128";
         std::int8_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::int8_t>::min());
      }
      {
         std::string toml_input = "127";
         std::int8_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::int8_t>::max());
      }
      {
         std::string toml_input = "-129";
         std::int8_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
      {
         std::string toml_input = "128";
         std::int8_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_decimal_uint8_boundaries"_test = [] {
      {
         std::string toml_input = "0";
         std::uint8_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::uint8_t>::min());
      }
      {
         std::string toml_input = "255";
         std::uint8_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::uint8_t>::max());
      }
      {
         std::string toml_input = "-1";
         std::uint8_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
      {
         std::string toml_input = "256";
         std::uint8_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_decimal_int16_boundaries"_test = [] {
      {
         std::string toml_input = "-32768";
         std::int16_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::int16_t>::min());
      }
      {
         std::string toml_input = "32767";
         std::int16_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::int16_t>::max());
      }
      {
         std::string toml_input = "-32769";
         std::int16_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
      {
         std::string toml_input = "32768";
         std::int16_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_decimal_uint16_boundaries"_test = [] {
      {
         std::string toml_input = "0";
         std::uint16_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::uint16_t>::min());
      }
      {
         std::string toml_input = "65535";
         std::uint16_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::uint16_t>::max());
      }
      {
         std::string toml_input = "-1";
         std::uint16_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
      {
         std::string toml_input = "65536";
         std::uint16_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_decimal_int32_boundaries"_test = [] {
      {
         std::string toml_input = "-2147483648";
         std::int32_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::int32_t>::min());
      }
      {
         std::string toml_input = "2147483647";
         std::int32_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::int32_t>::max());
      }
      {
         std::string toml_input = "-2147483649";
         std::int32_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
      {
         std::string toml_input = "2147483648";
         std::int32_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_decimal_uint32_boundaries"_test = [] {
      {
         std::string toml_input = "0";
         std::uint32_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::uint32_t>::min());
      }
      {
         std::string toml_input = "4294967295";
         std::uint32_t value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == std::numeric_limits<std::uint32_t>::max());
      }
      {
         std::string toml_input = "-1";
         std::uint32_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
      {
         std::string toml_input = "4294967296";
         std::uint32_t value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_decimal_with_underscores_integer"_test = [] {
      {
         std::string toml_input = "1_234_567";
         int value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == 1234567);
      }
      {
         std::string toml_input = "-1_234_567";
         int value{};
         expect(not glz::read_toml(value, toml_input));
         expect(value == -1234567);
      }
   };

   "read_hex_with_underscores_integer"_test = [] {
      std::string toml_input = "0xDEAD_BEEF";
      std::uint32_t value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 0xDEADBEEF);
   };

   "read_binary_with_underscores_integer"_test = [] {
      std::string toml_input = "0b1010_0101_1111";
      std::uint32_t value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 0b101001011111);
   };

   "read_octal_with_underscores_integer"_test = [] {
      std::string toml_input = "0o12_34_70";
      std::uint32_t value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 0123470);
   };

   "read_wrong_multiple_signs_integer"_test = [] {
      for (const auto input : {"+-1", "-+1", "--1", "++1"}) {
         std::string toml_input = input;
         int value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_wrong_sign_without_digits_integer"_test = [] {
      for (const auto input : {"+", "-", "+_", "-_"}) {
         std::string toml_input = input;
         int value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_wrong_prefixed_missing_digits_integer"_test = [] {
      for (const auto input : {"0x", "0b", "0o", "0x_", "0b_", "0o_"}) {
         std::string toml_input = input;
         int value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_wrong_prefixed_trailing_underscore_integer"_test = [] {
      for (const auto input : {"0xAB_", "0b101_", "0o77_"}) {
         std::string toml_input = input;
         int value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_wrong_prefixed_double_underscore_integer"_test = [] {
      for (const auto input : {"0xA__B", "0b10__10", "0o1__2"}) {
         std::string toml_input = input;
         int value{};
         auto error = glz::read_toml(value, toml_input);
         expect(error);
         expect(error == glz::error_code::parse_number_failure);
      }
   };

   "read_float"_test = [] {
      std::string toml_input = "3.14159";
      double value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == 3.14159);
   };

   "read_string"_test = [] {
      std::string toml_input = R"("Hello TOML")";
      std::string value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == "Hello TOML");
   };

   "write_explicit_string_view"_test = [] {
      struct explicit_string_view_type
      {
         std::string storage{};

         explicit explicit_string_view_type(std::string_view s) : storage(s) {}

         explicit operator std::string_view() const noexcept { return storage; }
      };

      explicit_string_view_type value{std::string_view{"explicit"}};

      std::string buffer{};
      expect(not glz::write_toml(value, buffer));
      expect(buffer == R"("explicit")");

      buffer.clear();
      expect(not glz::write<glz::opt_true<glz::opts{.format = glz::TOML}, glz::raw_string_opt_tag{}>>(value, buffer));
      expect(buffer == R"("explicit")");
   };

   "read_boolean_true"_test = [] {
      std::string toml_input = "true";
      bool value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == true);
   };

   "read_boolean_false"_test = [] {
      std::string toml_input = "false";
      bool value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value == false);
   };

   "read_array"_test = [] {
      std::string toml_input = "[1, 2, 3, 4]";
      std::vector<int> value{};
      expect(not glz::read_toml(value, toml_input));
      expect(value.size() == 4);
      expect(value[0] == 1);
      expect(value[1] == 2);
      expect(value[2] == 3);
      expect(value[3] == 4);
   };

   "scalar_int"_test = [] {
      int i = 42;
      std::string buffer{};
      expect(not glz::write_toml(i, buffer));
      expect(buffer == "42");
   };

   "simple_array"_test = [] {
      std::vector<int> v = {1, 2, 3, 4};
      std::string buffer{};
      expect(not glz::write_toml(v, buffer));
      expect(buffer == "[1, 2, 3, 4]");
   };

   "writable_map"_test = [] {
      std::map<std::string, int> m = {{"a", 1}, {"b", 2}};
      std::string buffer{};
      expect(not glz::write_toml(m, buffer));
      // std::map orders keys lexicographically, so we expect:
      expect(buffer == R"(a = 1
b = 2)");
   };

   "tuple_test"_test = [] {
      std::tuple<int, std::string> t = {100, "hello"};
      std::string buffer{};
      expect(not glz::write_toml(t, buffer));
      expect(buffer == R"([100, "hello"])");
   };

   // Test writing a string that contains quotes and backslashes.
   "escape_string"_test = [] {
      std::string s = "Line \"quoted\" and \\ backslash";
      std::string buffer{};
      expect(not glz::write_toml(s, buffer));
      // The expected output escapes the quote and backslash, and encloses the result in quotes.
      expect(buffer == R"("Line \"quoted\" and \\ backslash")");
   };

   // Test writing a nested structure.
   // TOML spec: scalars should be written before tables for correct parsing
   "write_nested_struct"_test = [] {
      simple_container c{};
      std::string buffer{};
      expect(not glz::write_toml(c, buffer));
      expect(buffer == R"(value = 5.5
[inner]
x = 10
y = "test"
)");
   };

   "read_wrong_format_nested"_test = [] {
      advanced_container sc{};
      std::string buffer{R"([inner]
x = 10
y = "test"

value = 5.5)"};
      auto error = glz::read_toml(sc, buffer);
      expect(error); // Expect an error because the format is not correct for TOML. root value should be before nested
                     // table.
      expect(error == glz::error_code::unknown_key);
   };

   "read_nested_struct"_test = [] {
      simple_container sc{};
      std::string buffer{R"(value = 5.6

[inner]
x = 11
y = "test1"
)"};
      expect(not glz::read_toml(sc, buffer));
      expect(sc.inner.x == 11);
      expect(sc.inner.y == "test1");
      expect(sc.value == 5.6);
   };

   "read_advanced_nested_struct"_test = [] {
      advanced_container ac{};
      std::string buffer{R"(value = 5.6

[inner]
x = 11
y = "test1"

[inner_two]
x = 12
y = "test2"
)"};
      expect(not glz::read_toml(ac, buffer));
      expect(ac.inner.x == 11);
      expect(ac.inner.y == "test1");
      expect(ac.inner_two.x == 12);
      expect(ac.inner_two.y == "test2");
      expect(ac.value == 5.6);
   };

   "read_advanced_nested_struct"_test = [] {
      dotted_access_struct dac{};
      std::string buffer{R"(l2.l1.value = 1)"};
      expect(not glz::read_toml(dac, buffer));
      expect(dac.l2.l1.value == 1);
   };

   "ignore_unknown_dotted_key"_test = [] {
      dotted_unknown_root result{};
      result.key.value = "initial";
      const std::string toml_input = R"(key.other_value = "string")";

      const auto error = glz::read<glz::opts{.format = glz::TOML, .error_on_unknown_keys = false}>(result, toml_input);

      expect(not error);
      expect(result.key.value == "initial");
   };

   "ignore_unknown_dotted_key_type_mismatch"_test = [] {
      dotted_unknown_root result{};
      result.key.value = "initial";
      const std::string toml_input = R"(key.other_value = 1
key.value = "string")";

      const auto error = glz::read<glz::opts{.format = glz::TOML, .error_on_unknown_keys = false}>(result, toml_input);

      expect(not error);
      expect(result.key.value == "string");
   };

   "ignore_unknown_multiline_basic_string"_test = [] {
      dotted_unknown_root result{};
      result.key.value = "initial";
      const std::string toml_input = R"(key.other_value = """first
second"""
key.value = "string")";

      const auto error = glz::read<glz::opts{.format = glz::TOML, .error_on_unknown_keys = false}>(result, toml_input);

      expect(not error);
      expect(result.key.value == "string");
   };

   "ignore_unknown_multiline_literal_string"_test = [] {
      dotted_unknown_root result{};
      result.key.value = "initial";
      const std::string toml_input = R"(key.other_value = '''first
second'''
key.value = "string")";

      const auto error = glz::read<glz::opts{.format = glz::TOML, .error_on_unknown_keys = false}>(result, toml_input);

      expect(not error);
      expect(result.key.value == "string");
   };

   "ignore_unknown_array_value"_test = [] {
      dotted_unknown_root result{};
      result.key.value = "initial";
      const std::string toml_input = R"(key.other_value = [1, 2, 3]
key.value = "string")";

      const auto error = glz::read<glz::opts{.format = glz::TOML, .error_on_unknown_keys = false}>(result, toml_input);

      expect(not error);
      expect(result.key.value == "string");
   };

   "ignore_unknown_inline_table"_test = [] {
      simple_value_struct result{};
      const std::string toml_input = R"(other = { nested = "value", deeper = { inner = 1 } }
value = "string")";

      const auto error = glz::read<glz::opts{.format = glz::TOML, .error_on_unknown_keys = false}>(result, toml_input);

      expect(not error);
      expect(result.value == "string");
   };

   // Test writing a boolean value.
   "boolean_value"_test = [] {
      bool b = true;
      std::string buffer{};
      expect(not glz::write_toml(b, buffer));
      expect(buffer == "true");
   };

   // Test writing an empty array.
   "empty_array"_test = [] {
      std::vector<int> empty{};
      std::string buffer{};
      expect(not glz::write_toml(empty, buffer));
      expect(buffer == "[]");
   };

   // Test writing an empty map.
   "empty_map"_test = [] {
      std::map<std::string, int> empty{};
      std::string buffer{};
      expect(not glz::write_toml(empty, buffer));
      expect(buffer == "");
   };

   // Test writing a vector of booleans.
   "vector_of_bool"_test = [] {
      std::vector<bool> vb = {true, false, true};
      std::string buffer{};
      expect(not glz::write_toml(vb, buffer));
      expect(buffer == "[true, false, true]");
   };

   // Test writing an optional that contains a value.
   "optional_present"_test = [] {
      std::optional<int> opt = 42;
      std::string buffer{};
      expect(not glz::write_toml(opt, buffer));
      expect(buffer == "42");
   };

   // Test writing an optional that is null.
   "optional_null"_test = [] {
      std::optional<int> opt = std::nullopt;
      std::string buffer{};
      expect(not glz::write_toml(opt, buffer));
      // Assuming that a null optional is skipped and produces an empty output.
      expect(buffer == "");
   };

   // Test writing a structure with an optional member (present).
   "optional_struct_present"_test = [] {
      optional_struct os{};
      std::string buffer{};
      expect(not glz::write_toml(os, buffer));
      expect(buffer == "maybe = 99");
   };

   // Test writing a structure with an optional member (null).
   "optional_struct_null"_test = [] {
      optional_struct os{};
      os.maybe = std::nullopt;
      std::string buffer{};
      expect(not glz::write_toml(os, buffer));
      // If all members are null (or skipped) then the output is empty.
      expect(buffer == "");
   };

   "read_inline_table"_test = [] {
      std::string toml_input = R"(name = "Test Person"
inline_data = { key1 = "value1", key2 = 100 })";
      struct_with_inline_table s{};
      auto error = glz::read_toml(s, toml_input);
      expect(!error) << glz::format_error(error, toml_input);
      expect(s.name == "Test Person");
      expect(s.inline_data.key1 == "value1");
      expect(s.inline_data.key2 == 100);
   };

   "read_complex_strings"_test = [] {
      std::string toml_input = R"(
basic_multiline = """
Roses are red
Violets are blue"""
literal_multiline = '''
The first line.
  The second line.
    The third line.'''
literal_multiline_with_quotes = '''He said "She said 'It is so.''"'''
)";
      complex_strings_struct s{};
      auto error = glz::read_toml(s, toml_input);
      expect(!error) << glz::format_error(error, toml_input);
      expect(s.basic_multiline == "Roses are red\nViolets are blue");
      expect(s.literal_multiline == "The first line.\n  The second line.\n    The third line.");
      expect(s.literal_multiline_with_quotes == "He said \"She said 'It is so.''\"");
   };

   "read_with_comments"_test = [] {
      std::string toml_input = R"(
# This is a full line comment
a = 123 # This is an end-of-line comment
# Another comment
b = "test string" # another eol comment
)";
      comment_test_struct s{};
      auto error = glz::read_toml(s, toml_input);
      expect(!error) << glz::format_error(error, toml_input);
      expect(s.a == 123);
      expect(s.b == "test string");
   };

   "read_non_null_terminated"_test = [] {
      std::string buffer_with_extra = "value = 123GARBAGE_DATA";
      // Create a string_view that does not include "GARBAGE_DATA" and is not null-terminated
      // within the view itself.
      std::string_view toml_data(buffer_with_extra.data(), 11); // "value = 123"

      non_null_term_struct s_val{};
      auto error = glz::read_toml(s_val, toml_data);
      expect(!error) << glz::format_error(error, toml_data);
      expect(s_val.value == 123);

      std::string buffer_just_value = "value = 456"; // Null terminated by string constructor
      non_null_term_struct s_val2{};
      error = glz::read_toml(s_val2, buffer_just_value);
      expect(!error) << glz::format_error(error, buffer_just_value);
      expect(s_val2.value == 456);
   };

   // ========== Enum serialization tests ==========

   "write_enum_basic"_test = [] {
      Color c = Color::Green;
      auto result = glz::write_toml(c);
      expect(result.has_value());
      expect(result.value() == R"("Green")");
   };

   "read_enum_basic"_test = [] {
      Color c{};
      std::string input = R"("Blue")";
      auto error = glz::read_toml(c, input);
      expect(!error) << glz::format_error(error, input);
      expect(c == Color::Blue);
   };

   "enum_roundtrip"_test = [] {
      for (auto color : {Color::Red, Color::Green, Color::Blue}) {
         auto result = glz::write_toml(color);
         expect(result.has_value());

         Color parsed{};
         auto error = glz::read_toml(parsed, result.value());
         expect(!error) << glz::format_error(error, result.value());
         expect(parsed == color);
      }
   };

   "write_enum_all_values"_test = [] {
      {
         Status s = Status::Pending;
         auto result = glz::write_toml(s);
         expect(result.has_value());
         expect(result.value() == R"("Pending")");
      }
      {
         Status s = Status::Active;
         auto result = glz::write_toml(s);
         expect(result.has_value());
         expect(result.value() == R"("Active")");
      }
      {
         Status s = Status::Completed;
         auto result = glz::write_toml(s);
         expect(result.has_value());
         expect(result.value() == R"("Completed")");
      }
      {
         Status s = Status::Cancelled;
         auto result = glz::write_toml(s);
         expect(result.has_value());
         expect(result.value() == R"("Cancelled")");
      }
   };

   "read_enum_all_values"_test = [] {
      {
         Status s{};
         std::string input = R"("Pending")";
         auto error = glz::read_toml(s, input);
         expect(!error) << glz::format_error(error, input);
         expect(s == Status::Pending);
      }
      {
         Status s{};
         std::string input = R"("Active")";
         auto error = glz::read_toml(s, input);
         expect(!error) << glz::format_error(error, input);
         expect(s == Status::Active);
      }
      {
         Status s{};
         std::string input = R"("Completed")";
         auto error = glz::read_toml(s, input);
         expect(!error) << glz::format_error(error, input);
         expect(s == Status::Completed);
      }
      {
         Status s{};
         std::string input = R"("Cancelled")";
         auto error = glz::read_toml(s, input);
         expect(!error) << glz::format_error(error, input);
         expect(s == Status::Cancelled);
      }
   };

   "enum_custom_names"_test = [] {
      // Write with custom names
      {
         LogLevel level = LogLevel::Warning;
         auto result = glz::write_toml(level);
         expect(result.has_value());
         expect(result.value() == R"("warning")");
      }
      // Read with custom names
      {
         LogLevel level{};
         std::string input = R"("error")";
         auto error = glz::read_toml(level, input);
         expect(!error) << glz::format_error(error, input);
         expect(level == LogLevel::Error);
      }
      // Roundtrip all custom-named values
      for (auto level : {LogLevel::Debug, LogLevel::Info, LogLevel::Warning, LogLevel::Error}) {
         auto result = glz::write_toml(level);
         expect(result.has_value());

         LogLevel parsed{};
         auto error = glz::read_toml(parsed, result.value());
         expect(!error) << glz::format_error(error, result.value());
         expect(parsed == level);
      }
   };

   "enum_single_value"_test = [] {
      // Single-value enum edge case
      SingleEnum e = SingleEnum::OnlyValue;
      auto result = glz::write_toml(e);
      expect(result.has_value());
      expect(result.value() == R"("OnlyValue")");

      SingleEnum parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == SingleEnum::OnlyValue);
   };

   "raw_enum_write"_test = [] {
      // Raw enum without glz::meta should serialize as number
      RawEnum e = RawEnum::B;
      auto result = glz::write_toml(e);
      expect(result.has_value());
      expect(result.value() == "1");
   };

   "raw_enum_read"_test = [] {
      // Raw enum should read from number
      RawEnum e{};
      std::string input = "2";
      auto error = glz::read_toml(e, input);
      expect(!error) << glz::format_error(error, input);
      expect(e == RawEnum::C);
   };

   "raw_enum_roundtrip"_test = [] {
      for (auto e : {RawEnum::A, RawEnum::B, RawEnum::C}) {
         auto result = glz::write_toml(e);
         expect(result.has_value());

         RawEnum parsed{};
         auto error = glz::read_toml(parsed, result.value());
         expect(!error) << glz::format_error(error, result.value());
         expect(parsed == e);
      }
   };

   "struct_with_enum_write"_test = [] {
      config_with_enums config{};
      config.name = "test_config";
      config.color = Color::Blue;
      config.status = Status::Active;
      config.priority = 5;

      auto result = glz::write_toml(config);
      expect(result.has_value());
      expect(result.value() == R"(name = "test_config"
color = "Blue"
status = "Active"
priority = 5)");
   };

   "struct_with_enum_read"_test = [] {
      std::string input = R"(name = "my_config"
color = "Green"
status = "Completed"
priority = 10)";

      config_with_enums config{};
      auto error = glz::read_toml(config, input);
      expect(!error) << glz::format_error(error, input);
      expect(config.name == "my_config");
      expect(config.color == Color::Green);
      expect(config.status == Status::Completed);
      expect(config.priority == 10);
   };

   "struct_with_enum_roundtrip"_test = [] {
      config_with_enums original{};
      original.name = "roundtrip_test";
      original.color = Color::Red;
      original.status = Status::Cancelled;
      original.priority = 99;

      auto result = glz::write_toml(original);
      expect(result.has_value());

      config_with_enums parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   "enum_invalid_value"_test = [] {
      Color c{};
      std::string input = R"("InvalidColor")";
      auto error = glz::read_toml(c, input);
      expect(error);
      expect(error == glz::error_code::unexpected_enum);
   };

   "enum_missing_quote"_test = [] {
      Color c{};
      std::string input = "Red"; // Missing quotes
      auto error = glz::read_toml(c, input);
      expect(error);
      expect(error == glz::error_code::expected_quote);
   };

   "enum_empty_string"_test = [] {
      Color c{};
      std::string input = R"("")"; // Empty string
      auto error = glz::read_toml(c, input);
      expect(error);
      expect(error == glz::error_code::unexpected_enum);
   };

   // ========== std::chrono duration tests ==========

   "duration_seconds_write"_test = [] {
      std::chrono::seconds s{42};
      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value() == "42");
   };

   "duration_seconds_read"_test = [] {
      std::chrono::seconds s{};
      std::string input = "100";
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.count() == 100);
   };

   "duration_milliseconds_write"_test = [] {
      std::chrono::milliseconds ms{1500};
      auto result = glz::write_toml(ms);
      expect(result.has_value());
      expect(result.value() == "1500");
   };

   "duration_milliseconds_read"_test = [] {
      std::chrono::milliseconds ms{};
      std::string input = "2500";
      auto error = glz::read_toml(ms, input);
      expect(!error) << glz::format_error(error, input);
      expect(ms.count() == 2500);
   };

   "duration_minutes_roundtrip"_test = [] {
      std::chrono::minutes original{60};
      auto result = glz::write_toml(original);
      expect(result.has_value());

      std::chrono::minutes parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   "duration_hours_roundtrip"_test = [] {
      std::chrono::hours original{24};
      auto result = glz::write_toml(original);
      expect(result.has_value());

      std::chrono::hours parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   "duration_negative_value"_test = [] {
      std::chrono::seconds s{-100};
      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value() == "-100");

      std::chrono::seconds parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed.count() == -100);
   };

   "duration_zero_value"_test = [] {
      std::chrono::seconds s{0};
      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value() == "0");

      std::chrono::seconds parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed.count() == 0);
   };

   "duration_struct_write"_test = [] {
      duration_test_struct s{};
      s.seconds_val = std::chrono::seconds{10};
      s.millis_val = std::chrono::milliseconds{500};
      s.minutes_val = std::chrono::minutes{5};
      s.hours_val = std::chrono::hours{2};

      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value() == R"(seconds_val = 10
millis_val = 500
minutes_val = 5
hours_val = 2)");
   };

   "duration_struct_read"_test = [] {
      std::string input = R"(seconds_val = 30
millis_val = 1000
minutes_val = 10
hours_val = 1)";

      duration_test_struct s{};
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.seconds_val.count() == 30);
      expect(s.millis_val.count() == 1000);
      expect(s.minutes_val.count() == 10);
      expect(s.hours_val.count() == 1);
   };

   "duration_struct_roundtrip"_test = [] {
      duration_test_struct original{};
      original.seconds_val = std::chrono::seconds{42};
      original.millis_val = std::chrono::milliseconds{12345};
      original.minutes_val = std::chrono::minutes{60};
      original.hours_val = std::chrono::hours{24};

      auto result = glz::write_toml(original);
      expect(result.has_value());

      duration_test_struct parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   // ========== std::chrono::system_clock::time_point tests (native TOML datetime) ==========

   "system_time_write_basic"_test = [] {
      using namespace std::chrono;
      system_clock::time_point tp = sys_days{year{2024} / month{6} / day{15}} + hours{10} + minutes{30} + seconds{45};

      auto result = glz::write_toml(tp);
      expect(result.has_value());
      // Should contain the datetime without quotes (native TOML format)
      expect(result.value().find("2024-06-15T10:30:45") != std::string::npos);
      expect(result.value().find('"') == std::string::npos); // No quotes
   };

   "system_time_read_with_Z"_test = [] {
      using namespace std::chrono;
      system_clock::time_point tp{};
      std::string input = "2024-06-15T10:30:45Z";
      auto error = glz::read_toml(tp, input);
      expect(!error) << glz::format_error(error, input);

      auto expected = sys_days{year{2024} / month{6} / day{15}} + hours{10} + minutes{30} + seconds{45};
      expect(time_point_cast<seconds>(tp) == time_point_cast<seconds>(expected));
   };

   "system_time_read_local_datetime"_test = [] {
      // TOML local datetime (no timezone) - treated as UTC
      using namespace std::chrono;
      system_clock::time_point tp{};
      std::string input = "2024-06-15T10:30:45";
      auto error = glz::read_toml(tp, input);
      expect(!error) << glz::format_error(error, input);

      auto expected = sys_days{year{2024} / month{6} / day{15}} + hours{10} + minutes{30} + seconds{45};
      expect(time_point_cast<seconds>(tp) == time_point_cast<seconds>(expected));
   };

   "system_time_read_positive_offset"_test = [] {
      using namespace std::chrono;
      system_clock::time_point tp{};
      // +05:00 means local time is 5 hours ahead of UTC
      std::string input = "2024-06-15T10:30:45+05:00";
      auto error = glz::read_toml(tp, input);
      expect(!error) << glz::format_error(error, input);

      // 10:30:45+05:00 = 05:30:45Z
      auto expected = sys_days{year{2024} / month{6} / day{15}} + hours{5} + minutes{30} + seconds{45};
      expect(time_point_cast<seconds>(tp) == time_point_cast<seconds>(expected));
   };

   "system_time_read_negative_offset"_test = [] {
      using namespace std::chrono;
      system_clock::time_point tp{};
      // -08:00 means local time is 8 hours behind UTC
      std::string input = "2024-06-15T10:30:45-08:00";
      auto error = glz::read_toml(tp, input);
      expect(!error) << glz::format_error(error, input);

      // 10:30:45-08:00 = 18:30:45Z
      auto expected = sys_days{year{2024} / month{6} / day{15}} + hours{18} + minutes{30} + seconds{45};
      expect(time_point_cast<seconds>(tp) == time_point_cast<seconds>(expected));
   };

   "system_time_read_fractional_seconds"_test = [] {
      using namespace std::chrono;
      system_clock::time_point tp{};
      std::string input = "2024-06-15T10:30:45.123456Z";
      auto error = glz::read_toml(tp, input);
      expect(!error) << glz::format_error(error, input);

      auto expected_base = sys_days{year{2024} / month{6} / day{15}} + hours{10} + minutes{30} + seconds{45};
      // Check that we got roughly the right time (within a second)
      expect(time_point_cast<seconds>(tp) == time_point_cast<seconds>(expected_base));
   };

   "system_time_read_without_seconds"_test = [] {
      // TOML allows omitting seconds
      using namespace std::chrono;
      system_clock::time_point tp{};
      std::string input = "2024-06-15T10:30Z";
      auto error = glz::read_toml(tp, input);
      expect(!error) << glz::format_error(error, input);

      auto expected = sys_days{year{2024} / month{6} / day{15}} + hours{10} + minutes{30};
      expect(time_point_cast<seconds>(tp) == time_point_cast<seconds>(expected));
   };

   "system_time_read_space_delimiter"_test = [] {
      // TOML allows space instead of T
      using namespace std::chrono;
      system_clock::time_point tp{};
      std::string input = "2024-06-15 10:30:45Z";
      auto error = glz::read_toml(tp, input);
      expect(!error) << glz::format_error(error, input);

      auto expected = sys_days{year{2024} / month{6} / day{15}} + hours{10} + minutes{30} + seconds{45};
      expect(time_point_cast<seconds>(tp) == time_point_cast<seconds>(expected));
   };

   "system_time_read_lowercase_t"_test = [] {
      using namespace std::chrono;
      system_clock::time_point tp{};
      std::string input = "2024-06-15t10:30:45z";
      auto error = glz::read_toml(tp, input);
      expect(!error) << glz::format_error(error, input);

      auto expected = sys_days{year{2024} / month{6} / day{15}} + hours{10} + minutes{30} + seconds{45};
      expect(time_point_cast<seconds>(tp) == time_point_cast<seconds>(expected));
   };

   "system_time_struct_write"_test = [] {
      using namespace std::chrono;
      system_time_test_struct s{};
      s.timestamp = sys_days{year{2024} / month{12} / day{25}} + hours{23} + minutes{59} + seconds{59};
      s.value = 42;

      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value().find("2024-12-25T23:59:59") != std::string::npos);
      expect(result.value().find("value = 42") != std::string::npos);
   };

   "system_time_struct_read"_test = [] {
      using namespace std::chrono;
      std::string input = R"(timestamp = 2024-12-25T23:59:59Z
value = 100)";

      system_time_test_struct s{};
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);

      auto expected = sys_days{year{2024} / month{12} / day{25}} + hours{23} + minutes{59} + seconds{59};
      expect(time_point_cast<seconds>(s.timestamp) == time_point_cast<seconds>(expected));
      expect(s.value == 100);
   };

   "system_time_roundtrip"_test = [] {
      using namespace std::chrono;
      system_clock::time_point original =
         sys_days{year{2030} / month{1} / day{1}} + hours{12} + minutes{0} + seconds{0};

      auto result = glz::write_toml(original);
      expect(result.has_value());

      system_clock::time_point parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(time_point_cast<seconds>(parsed) == time_point_cast<seconds>(original));
   };

   "chrono_combined_struct_roundtrip"_test = [] {
      using namespace std::chrono;
      chrono_combined_struct original{};
      original.name = "test_config";
      original.timeout = seconds{30};
      original.created_at = sys_days{year{2024} / month{6} / day{15}} + hours{10} + minutes{30} + seconds{45};
      original.latency = milliseconds{150};

      auto result = glz::write_toml(original);
      expect(result.has_value());

      chrono_combined_struct parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed.name == original.name);
      expect(parsed.timeout == original.timeout);
      expect(time_point_cast<seconds>(parsed.created_at) == time_point_cast<seconds>(original.created_at));
      expect(parsed.latency == original.latency);
   };

   // ========== std::set tests ==========

   "set_int_write"_test = [] {
      std::set<int> s = {1, 2, 3};
      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value() == "[1, 2, 3]");
   };

   "set_int_read"_test = [] {
      std::set<int> s{};
      std::string input = "[3, 1, 2]";
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.size() == 3);
      expect(s.contains(1));
      expect(s.contains(2));
      expect(s.contains(3));
   };

   "set_string_write"_test = [] {
      std::set<std::string> s = {"apple", "banana", "cherry"};
      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value() == R"(["apple", "banana", "cherry"])");
   };

   "set_string_read"_test = [] {
      std::set<std::string> s{};
      std::string input = R"(["cherry", "apple", "banana"])";
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.size() == 3);
      expect(s.contains("apple"));
      expect(s.contains("banana"));
      expect(s.contains("cherry"));
   };

   "set_empty_write"_test = [] {
      std::set<int> s{};
      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value() == "[]");
   };

   "set_empty_read"_test = [] {
      std::set<int> s{1, 2, 3}; // Pre-populate
      std::string input = "[]";
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.empty());
   };

   "set_roundtrip"_test = [] {
      std::set<int> original = {10, 20, 30, 40, 50};
      auto result = glz::write_toml(original);
      expect(result.has_value());

      std::set<int> parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   "set_duplicates_in_input"_test = [] {
      // Sets should handle duplicate values (they just get deduplicated)
      std::set<int> s{};
      std::string input = "[1, 2, 2, 3, 3, 3]";
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.size() == 3);
      expect(s.contains(1));
      expect(s.contains(2));
      expect(s.contains(3));
   };

   "set_struct_write"_test = [] {
      set_test_struct s{};
      s.int_set = {1, 2, 3};
      s.string_set = {"a", "b", "c"};

      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value().find("int_set = [1, 2, 3]") != std::string::npos);
      expect(result.value().find(R"(string_set = ["a", "b", "c"])") != std::string::npos);
   };

   "set_struct_read"_test = [] {
      std::string input = R"(int_set = [3, 2, 1]
string_set = ["z", "y", "x"])";

      set_test_struct s{};
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.int_set.size() == 3);
      expect(s.int_set.contains(1));
      expect(s.int_set.contains(2));
      expect(s.int_set.contains(3));
      expect(s.string_set.size() == 3);
      expect(s.string_set.contains("x"));
      expect(s.string_set.contains("y"));
      expect(s.string_set.contains("z"));
   };

   "set_struct_roundtrip"_test = [] {
      set_test_struct original{};
      original.int_set = {100, 200, 300};
      original.string_set = {"foo", "bar", "baz"};

      auto result = glz::write_toml(original);
      expect(result.has_value());

      set_test_struct parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   // ========== std::unordered_set tests ==========

   "unordered_set_int_write"_test = [] {
      std::unordered_set<int> s = {1, 2, 3};
      auto result = glz::write_toml(s);
      expect(result.has_value());
      // Order is unspecified, but should contain all elements
      expect(result.value().find("1") != std::string::npos);
      expect(result.value().find("2") != std::string::npos);
      expect(result.value().find("3") != std::string::npos);
   };

   "unordered_set_int_read"_test = [] {
      std::unordered_set<int> s{};
      std::string input = "[3, 1, 2]";
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.size() == 3);
      expect(s.contains(1));
      expect(s.contains(2));
      expect(s.contains(3));
   };

   "unordered_set_empty_write"_test = [] {
      std::unordered_set<int> s{};
      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value() == "[]");
   };

   "unordered_set_empty_read"_test = [] {
      std::unordered_set<int> s{1, 2, 3}; // Pre-populate
      std::string input = "[]";
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.empty());
   };

   "unordered_set_roundtrip"_test = [] {
      std::unordered_set<int> original = {10, 20, 30, 40, 50};
      auto result = glz::write_toml(original);
      expect(result.has_value());

      std::unordered_set<int> parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   "unordered_set_struct_roundtrip"_test = [] {
      unordered_set_test_struct original{};
      original.int_uset = {100, 200, 300};

      auto result = glz::write_toml(original);
      expect(result.has_value());

      unordered_set_test_struct parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   // ========== Combined container tests ==========

   "combined_containers_write"_test = [] {
      combined_containers_struct s{};
      s.vec = {1, 2, 3};
      s.set = {4, 5, 6};
      s.arr = {7, 8, 9};

      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value().find("vec = [1, 2, 3]") != std::string::npos);
      expect(result.value().find("set = [4, 5, 6]") != std::string::npos);
      expect(result.value().find("arr = [7, 8, 9]") != std::string::npos);
   };

   "combined_containers_read"_test = [] {
      std::string input = R"(vec = [1, 2, 3]
set = [6, 5, 4]
arr = [7, 8, 9])";

      combined_containers_struct s{};
      auto error = glz::read_toml(s, input);
      expect(!error) << glz::format_error(error, input);
      expect(s.vec == std::vector<int>{1, 2, 3});
      expect(s.set == std::set<int>{4, 5, 6});
      expect(s.arr == std::array<int, 3>{7, 8, 9});
   };

   "combined_containers_roundtrip"_test = [] {
      combined_containers_struct original{};
      original.vec = {10, 20, 30};
      original.set = {40, 50, 60};
      original.arr = {70, 80, 90};

      auto result = glz::write_toml(original);
      expect(result.has_value());

      combined_containers_struct parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   // ========== Edge cases and error handling ==========

   "system_time_invalid_format"_test = [] {
      using namespace std::chrono;
      system_clock::time_point tp{};
      std::string input = "not-a-datetime";
      auto error = glz::read_toml(tp, input);
      expect(error);
   };

   "system_time_invalid_date"_test = [] {
      using namespace std::chrono;
      system_clock::time_point tp{};
      std::string input = "2024-13-45T25:61:61Z"; // Invalid month, day, hour, minute, second
      auto error = glz::read_toml(tp, input);
      expect(error);
   };

   "system_time_too_short"_test = [] {
      using namespace std::chrono;
      system_clock::time_point tp{};
      std::string input = "2024-06-15"; // Date only, no time (too short for time_point)
      auto error = glz::read_toml(tp, input);
      expect(error);
   };

   "set_nested_array"_test = [] {
      // Sets of complex types
      std::set<std::pair<int, int>> s{};
      // This tests that the implementation handles value types correctly
      // Note: std::pair may not work directly without meta, but this tests the concept
   };

   "duration_large_value"_test = [] {
      std::chrono::seconds s{999999999};
      auto result = glz::write_toml(s);
      expect(result.has_value());
      expect(result.value() == "999999999");

      std::chrono::seconds parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed.count() == 999999999);
   };

   // ========== TOML Local Date (year_month_day) tests ==========

   "local_date_write"_test = [] {
      using namespace std::chrono;
      year_month_day ymd{year{2024}, month{6}, day{15}};
      auto result = glz::write_toml(ymd);
      expect(result.has_value());
      expect(result.value() == "2024-06-15");
   };

   "local_date_read"_test = [] {
      using namespace std::chrono;
      year_month_day ymd{};
      std::string input = "2024-12-25";
      auto error = glz::read_toml(ymd, input);
      expect(!error) << glz::format_error(error, input);
      expect(ymd.year() == year{2024});
      expect(ymd.month() == month{12});
      expect(ymd.day() == day{25});
   };

   "local_date_roundtrip"_test = [] {
      using namespace std::chrono;
      year_month_day original{year{2030}, month{1}, day{1}};
      auto result = glz::write_toml(original);
      expect(result.has_value());

      year_month_day parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   "local_date_leap_year"_test = [] {
      using namespace std::chrono;
      year_month_day ymd{};
      std::string input = "2024-02-29"; // 2024 is a leap year
      auto error = glz::read_toml(ymd, input);
      expect(!error) << glz::format_error(error, input);
      expect(ymd.year() == year{2024});
      expect(ymd.month() == month{2});
      expect(ymd.day() == day{29});
      expect(ymd.ok());
   };

   "local_date_invalid"_test = [] {
      using namespace std::chrono;
      year_month_day ymd{};
      std::string input = "2024-02-30"; // Invalid date
      auto error = glz::read_toml(ymd, input);
      expect(error);
   };

   "local_date_struct_roundtrip"_test = [] {
      using namespace std::chrono;
      local_date_test_struct original{};
      original.date = year_month_day{year{2024}, month{6}, day{15}};
      original.value = 42;

      auto result = glz::write_toml(original);
      expect(result.has_value());

      local_date_test_struct parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed == original);
   };

   // ========== TOML Local Time (hh_mm_ss) tests ==========

   "local_time_write_seconds"_test = [] {
      using namespace std::chrono;
      hh_mm_ss<seconds> tod{hours{10} + minutes{30} + seconds{45}};
      auto result = glz::write_toml(tod);
      expect(result.has_value());
      expect(result.value() == "10:30:45");
   };

   "local_time_write_milliseconds"_test = [] {
      using namespace std::chrono;
      hh_mm_ss<milliseconds> tod{hours{10} + minutes{30} + seconds{45} + milliseconds{123}};
      auto result = glz::write_toml(tod);
      expect(result.has_value());
      expect(result.value() == "10:30:45.123");
   };

   "local_time_read_basic"_test = [] {
      using namespace std::chrono;
      hh_mm_ss<seconds> tod{seconds{0}};
      std::string input = "23:59:59";
      auto error = glz::read_toml(tod, input);
      expect(!error) << glz::format_error(error, input);
      expect(tod.hours().count() == 23);
      expect(tod.minutes().count() == 59);
      expect(tod.seconds().count() == 59);
   };

   "local_time_read_fractional"_test = [] {
      using namespace std::chrono;
      hh_mm_ss<milliseconds> tod{milliseconds{0}};
      std::string input = "12:30:45.500";
      auto error = glz::read_toml(tod, input);
      expect(!error) << glz::format_error(error, input);
      expect(tod.hours().count() == 12);
      expect(tod.minutes().count() == 30);
      expect(tod.seconds().count() == 45);
      expect(tod.subseconds().count() == 500);
   };

   "local_time_read_without_seconds"_test = [] {
      // TOML allows omitting seconds
      using namespace std::chrono;
      hh_mm_ss<seconds> tod{seconds{0}};
      std::string input = "14:30";
      auto error = glz::read_toml(tod, input);
      expect(!error) << glz::format_error(error, input);
      expect(tod.hours().count() == 14);
      expect(tod.minutes().count() == 30);
      expect(tod.seconds().count() == 0);
   };

   "local_time_roundtrip"_test = [] {
      using namespace std::chrono;
      hh_mm_ss<seconds> original{hours{8} + minutes{15} + seconds{30}};
      auto result = glz::write_toml(original);
      expect(result.has_value());

      hh_mm_ss<seconds> parsed{seconds{0}};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed.hours() == original.hours());
      expect(parsed.minutes() == original.minutes());
      expect(parsed.seconds() == original.seconds());
   };

   "local_time_midnight"_test = [] {
      using namespace std::chrono;
      hh_mm_ss<seconds> tod{seconds{0}};
      std::string input = "00:00:00";
      auto error = glz::read_toml(tod, input);
      expect(!error) << glz::format_error(error, input);
      expect(tod.hours().count() == 0);
      expect(tod.minutes().count() == 0);
      expect(tod.seconds().count() == 0);
   };

   "local_time_end_of_day"_test = [] {
      using namespace std::chrono;
      hh_mm_ss<seconds> tod{seconds{0}};
      std::string input = "23:59:59";
      auto error = glz::read_toml(tod, input);
      expect(!error) << glz::format_error(error, input);
      expect(tod.hours().count() == 23);
      expect(tod.minutes().count() == 59);
      expect(tod.seconds().count() == 59);
   };

   "local_time_invalid_hour"_test = [] {
      using namespace std::chrono;
      hh_mm_ss<seconds> tod{seconds{0}};
      std::string input = "25:00:00";
      auto error = glz::read_toml(tod, input);
      expect(error);
   };

   "local_time_invalid_minute"_test = [] {
      using namespace std::chrono;
      hh_mm_ss<seconds> tod{seconds{0}};
      std::string input = "12:60:00";
      auto error = glz::read_toml(tod, input);
      expect(error);
   };

   "local_time_struct_roundtrip"_test = [] {
      using namespace std::chrono;
      local_time_test_struct original{};
      original.time_sec = hh_mm_ss<seconds>{hours{10} + minutes{30} + seconds{45}};
      original.time_ms = hh_mm_ss<milliseconds>{hours{12} + minutes{0} + seconds{0} + milliseconds{500}};

      auto result = glz::write_toml(original);
      expect(result.has_value());

      local_time_test_struct parsed{};
      auto error = glz::read_toml(parsed, result.value());
      expect(!error) << glz::format_error(error, result.value());
      expect(parsed.time_sec.hours() == original.time_sec.hours());
      expect(parsed.time_sec.minutes() == original.time_sec.minutes());
      expect(parsed.time_sec.seconds() == original.time_sec.seconds());
      expect(parsed.time_ms.hours() == original.time_ms.hours());
      expect(parsed.time_ms.minutes() == original.time_ms.minutes());
      expect(parsed.time_ms.seconds() == original.time_ms.seconds());
      expect(parsed.time_ms.subseconds() == original.time_ms.subseconds());
   };
};

// Bounded buffer overflow tests for TOML format
namespace toml_bounded_buffer_tests
{
   struct simple_toml_obj
   {
      int x = 42;
      std::string name = "hello";
      bool active = true;
   };

   struct large_toml_obj
   {
      int x = 42;
      std::string long_name = "this is a very long string that definitely won't fit in a tiny buffer";
      std::vector<int> data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
      double value = 3.14159265358979;
   };

   struct toml_nested
   {
      int id = 1;
      ::nested child{};
   };

   struct toml_with_array
   {
      std::vector<int> numbers = {1, 2, 3, 4, 5};
   };
}

suite toml_bounded_buffer_overflow_tests = [] {
   using namespace toml_bounded_buffer_tests;

   "toml write to std::array with sufficient space succeeds"_test = [] {
      simple_toml_obj obj{};
      std::array<char, 512> buffer{};

      auto result = glz::write_toml(obj, buffer);
      expect(not result) << "write should succeed with sufficient buffer";
      expect(result.count > 0) << "count should be non-zero";
      expect(result.count < buffer.size()) << "count should be less than buffer size";

      std::string_view toml(buffer.data(), result.count);
      expect(toml.find("x = 42") != std::string_view::npos) << "TOML should contain x = 42";
   };

   "toml write to std::array that is too small returns buffer_overflow"_test = [] {
      large_toml_obj obj{};
      std::array<char, 10> buffer{};

      auto result = glz::write_toml(obj, buffer);
      expect(result.ec == glz::error_code::buffer_overflow) << "should return buffer_overflow error";
   };

   "toml write to std::span with sufficient space succeeds"_test = [] {
      simple_toml_obj obj{};
      std::array<char, 512> storage{};
      std::span<char> buffer(storage);

      auto result = glz::write_toml(obj, buffer);
      expect(not result) << "write should succeed with sufficient buffer";
      expect(result.count > 0) << "count should be non-zero";
   };

   "toml write to std::span that is too small returns buffer_overflow"_test = [] {
      large_toml_obj obj{};
      std::array<char, 5> storage{};
      std::span<char> buffer(storage);

      auto result = glz::write_toml(obj, buffer);
      expect(result.ec == glz::error_code::buffer_overflow) << "should return buffer_overflow error";
   };

   "toml write nested struct to bounded buffer"_test = [] {
      toml_nested obj{};
      std::array<char, 512> buffer{};

      auto result = glz::write_toml(obj, buffer);
      expect(not result) << "write should succeed";
      expect(result.count > 0) << "count should be non-zero";
   };

   "toml resizable buffer still works as before"_test = [] {
      simple_toml_obj obj{};
      std::string buffer;

      auto result = glz::write_toml(obj, buffer);
      expect(not result) << "write to resizable buffer should succeed";
      expect(buffer.size() > 0) << "buffer should have data";
   };

   "toml write array to bounded buffer"_test = [] {
      toml_with_array obj{};
      std::array<char, 512> buffer{};

      auto result = glz::write_toml(obj, buffer);
      expect(not result) << "write should succeed";
   };

   "toml write map to bounded buffer"_test = [] {
      std::map<std::string, int> obj{{"one", 1}, {"two", 2}, {"three", 3}};
      std::array<char, 512> buffer{};

      auto result = glz::write_toml(obj, buffer);
      expect(not result) << "write should succeed";
   };
};

// ========== Array-of-Tables test structures ==========

struct product
{
   std::string name{};
   int sku{};

   bool operator==(const product&) const = default;
};

template <>
struct glz::meta<product>
{
   using T = product;
   static constexpr auto value = object("name", &T::name, "sku", &T::sku);
};

struct catalog
{
   std::string store_name{};
   std::vector<product> products{};

   bool operator==(const catalog&) const = default;
};

template <>
struct glz::meta<catalog>
{
   using T = catalog;
   static constexpr auto value = object("store_name", &T::store_name, "products", &T::products);
};

struct fruit_variety
{
   std::string name{};

   bool operator==(const fruit_variety&) const = default;
};

template <>
struct glz::meta<fruit_variety>
{
   using T = fruit_variety;
   static constexpr auto value = object("name", &T::name);
};

struct fruit
{
   std::string name{};
   std::vector<fruit_variety> varieties{};

   bool operator==(const fruit&) const = default;
};

template <>
struct glz::meta<fruit>
{
   using T = fruit;
   static constexpr auto value = object("name", &T::name, "varieties", &T::varieties);
};

struct fruit_basket
{
   std::vector<fruit> fruits{};

   bool operator==(const fruit_basket&) const = default;
};

template <>
struct glz::meta<fruit_basket>
{
   using T = fruit_basket;
   static constexpr auto value = object("fruits", &T::fruits);
};

// Reflectable struct for array-of-tables
struct reflectable_item
{
   std::string id{};
   int count{};

   bool operator==(const reflectable_item&) const = default;
};

struct reflectable_container
{
   std::string name{};
   std::vector<reflectable_item> items{};

   bool operator==(const reflectable_container&) const = default;
};

// Struct for the TOML spec example test (needs external linkage)
struct simple_catalog
{
   std::vector<product> products{};

   bool operator==(const simple_catalog&) const = default;
};

template <>
struct glz::meta<simple_catalog>
{
   using T = simple_catalog;
   static constexpr auto value = object("products", &T::products);
};

// Structs for edge case tests (need external linkage)
struct item_with_tags
{
   std::string name{};
   std::vector<int> tags{};

   bool operator==(const item_with_tags&) const = default;
};

template <>
struct glz::meta<item_with_tags>
{
   using T = item_with_tags;
   static constexpr auto value = object("name", &T::name, "tags", &T::tags);
};

struct container_with_tags
{
   std::vector<item_with_tags> items{};

   bool operator==(const container_with_tags&) const = default;
};

template <>
struct glz::meta<container_with_tags>
{
   using T = container_with_tags;
   static constexpr auto value = object("items", &T::items);
};

struct mixed_container
{
   std::string title{};
   nested inner{};
   std::vector<product> items{};

   bool operator==(const mixed_container&) const = default;
};

template <>
struct glz::meta<mixed_container>
{
   using T = mixed_container;
   static constexpr auto value = object("title", &T::title, "inner", &T::inner, "items", &T::items);
};

suite array_of_tables_tests = [] {
   "write_array_of_tables_basic"_test = [] {
      catalog c{};
      c.store_name = "Hardware Store";
      c.products = {{"Hammer", 738594937}, {"Nail", 284758393}};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      // Scalar fields should come first, then array-of-tables
      expect(buffer == R"(store_name = "Hardware Store"
[[products]]
name = "Hammer"
sku = 738594937

[[products]]
name = "Nail"
sku = 284758393
)");
   };

   "write_array_of_tables_empty"_test = [] {
      catalog c{};
      c.store_name = "Empty Store";
      c.products = {};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      // Empty array should be written as inline []
      expect(buffer == R"(store_name = "Empty Store"
products = [])");
   };

   "read_array_of_tables_basic"_test = [] {
      std::string input = R"(store_name = "Hardware Store"
[[products]]
name = "Hammer"
sku = 738594937

[[products]]
name = "Nail"
sku = 284758393
)";

      catalog c{};
      expect(not glz::read_toml(c, input));

      expect(c.store_name == "Hardware Store");
      expect(c.products.size() == 2);
      expect(c.products[0].name == "Hammer");
      expect(c.products[0].sku == 738594937);
      expect(c.products[1].name == "Nail");
      expect(c.products[1].sku == 284758393);
   };

   "read_array_of_tables_single_element"_test = [] {
      std::string input = R"(store_name = "Single Item Store"
[[products]]
name = "Screwdriver"
sku = 123456
)";

      catalog c{};
      expect(not glz::read_toml(c, input));

      expect(c.store_name == "Single Item Store");
      expect(c.products.size() == 1);
      expect(c.products[0].name == "Screwdriver");
      expect(c.products[0].sku == 123456);
   };

   "roundtrip_array_of_tables"_test = [] {
      catalog original{};
      original.store_name = "Test Store";
      original.products = {{"Item1", 111}, {"Item2", 222}, {"Item3", 333}};

      std::string buffer{};
      expect(not glz::write_toml(original, buffer));

      catalog parsed{};
      expect(not glz::read_toml(parsed, buffer));

      expect(original == parsed);
   };

   "read_array_of_tables_toml_spec_example"_test = [] {
      // Example from TOML spec
      std::string input = R"([[products]]
name = "Hammer"
sku = 738594937

[[products]]

[[products]]
name = "Nail"
sku = 284758393
)";

      simple_catalog c{};
      expect(not glz::read_toml(c, input));

      expect(c.products.size() == 3);
      expect(c.products[0].name == "Hammer");
      expect(c.products[0].sku == 738594937);
      // Second element is empty (default values)
      expect(c.products[1].name == "");
      expect(c.products[1].sku == 0);
      expect(c.products[2].name == "Nail");
      expect(c.products[2].sku == 284758393);
   };

   "write_nested_array_of_tables"_test = [] {
      // Nested array-of-tables: fruits is an array, each fruit has varieties array
      fruit_basket basket{};
      basket.fruits = {{"apple", {{"red delicious"}, {"granny smith"}}}};

      std::string buffer{};
      expect(not glz::write_toml(basket, buffer));

      // Verify nested arrays use TOML-spec-compliant [[parent.child]] syntax
      expect(buffer.find("[[fruits]]") != std::string::npos);
      expect(buffer.find("name = \"apple\"") != std::string::npos);
      expect(buffer.find("[[fruits.varieties]]") != std::string::npos); // Full dotted path
      expect(buffer.find("name = \"red delicious\"") != std::string::npos);
      expect(buffer.find("name = \"granny smith\"") != std::string::npos);
   };

   "reflectable_array_of_tables_write"_test = [] {
      reflectable_container c{};
      c.name = "Test Container";
      c.items = {{"A", 1}, {"B", 2}};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      expect(buffer.find("name = \"Test Container\"") != std::string::npos);
      expect(buffer.find("[[items]]") != std::string::npos);
      expect(buffer.find("id = \"A\"") != std::string::npos);
      expect(buffer.find("id = \"B\"") != std::string::npos);
   };

   "reflectable_array_of_tables_read"_test = [] {
      std::string input = R"(name = "Parsed Container"
[[items]]
id = "X"
count = 10

[[items]]
id = "Y"
count = 20
)";

      reflectable_container c{};
      expect(not glz::read_toml(c, input));

      expect(c.name == "Parsed Container");
      expect(c.items.size() == 2);
      expect(c.items[0].id == "X");
      expect(c.items[0].count == 10);
      expect(c.items[1].id == "Y");
      expect(c.items[1].count == 20);
   };

   "reflectable_array_of_tables_roundtrip"_test = [] {
      reflectable_container original{};
      original.name = "Roundtrip Test";
      original.items = {{"First", 100}, {"Second", 200}};

      std::string buffer{};
      expect(not glz::write_toml(original, buffer));

      reflectable_container parsed{};
      expect(not glz::read_toml(parsed, buffer));

      expect(original == parsed);
   };

   // ========== Edge Case Tests ==========

   "read_array_of_tables_at_file_start"_test = [] {
      // Array-of-tables can appear at the start of a file without preceding scalars
      std::string input = R"([[products]]
name = "First"
sku = 100

[[products]]
name = "Second"
sku = 200
)";

      simple_catalog c{};
      expect(not glz::read_toml(c, input));

      expect(c.products.size() == 2);
      expect(c.products[0].name == "First");
      expect(c.products[1].name == "Second");
   };

   "read_array_of_tables_with_comments"_test = [] {
      // Comments should be ignored around array-of-tables headers
      std::string input = R"(store_name = "Test"
# Comment before array-of-tables
[[products]]
name = "Item1"
sku = 1
# Comment between entries

[[products]]
# Comment after header
name = "Item2"
sku = 2
)";

      catalog c{};
      expect(not glz::read_toml(c, input));

      expect(c.store_name == "Test");
      expect(c.products.size() == 2);
      expect(c.products[0].name == "Item1");
      expect(c.products[1].name == "Item2");
   };

   "read_array_of_tables_multiple_empty"_test = [] {
      // Multiple consecutive empty array-of-tables entries
      std::string input = R"([[products]]
[[products]]
[[products]]
name = "OnlyThird"
sku = 3
)";

      simple_catalog c{};
      expect(not glz::read_toml(c, input));

      expect(c.products.size() == 3);
      expect(c.products[0].name == "");
      expect(c.products[0].sku == 0);
      expect(c.products[1].name == "");
      expect(c.products[1].sku == 0);
      expect(c.products[2].name == "OnlyThird");
      expect(c.products[2].sku == 3);
   };

   "read_array_of_tables_with_whitespace"_test = [] {
      // Whitespace in various positions should be handled
      std::string input = R"(  [[  products  ]]
name = "Spaced"
sku = 42
)";

      simple_catalog c{};
      expect(not glz::read_toml(c, input));

      expect(c.products.size() == 1);
      expect(c.products[0].name == "Spaced");
   };

   "read_array_of_tables_error_missing_bracket"_test = [] {
      // Missing closing bracket should error
      std::string input = R"([[products]
name = "Bad"
)";

      simple_catalog c{};
      auto error = glz::read_toml(c, input);
      expect(error);
      expect(error == glz::error_code::syntax_error);
   };

   "read_array_of_tables_error_single_bracket"_test = [] {
      // Using single bracket when expecting array-of-tables should be handled
      // This is a normal table, not array-of-tables, so it would try to write to "products" as a table
      std::string input = R"([products]
name = "NotArray"
)";

      simple_catalog c{};
      auto error = glz::read_toml(c, input);
      // This should error because products is an array, not a single object
      expect(error);
   };

   "write_array_of_tables_with_inline_array_field"_test = [] {
      // Array-of-tables where each element has an inline array field
      container_with_tags c{};
      c.items = {{"First", {1, 2, 3}}, {"Second", {4, 5}}};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      // Should have [[items]] with inline array tags = [...]
      expect(buffer.find("[[items]]") != std::string::npos);
      expect(buffer.find("tags = [1, 2, 3]") != std::string::npos);
      expect(buffer.find("tags = [4, 5]") != std::string::npos);
   };

   "nested_array_of_tables_roundtrip"_test = [] {
      // Complete roundtrip for nested array-of-tables with TOML-spec-compliant [[parent.child]] syntax
      fruit_basket original{};
      original.fruits = {
         {"apple", {{"red delicious"}, {"granny smith"}, {"fuji"}}},
         {"banana", {{"cavendish"}}},
         {"orange", {}} // Empty varieties
      };

      std::string buffer{};
      expect(not glz::write_toml(original, buffer));

      // Verify spec-compliant output
      expect(buffer.find("[[fruits]]") != std::string::npos);
      expect(buffer.find("[[fruits.varieties]]") != std::string::npos);

      fruit_basket parsed{};
      expect(not glz::read_toml(parsed, buffer));

      expect(parsed.fruits.size() == 3);
      expect(parsed.fruits[0].name == "apple");
      expect(parsed.fruits[0].varieties.size() == 3);
      expect(parsed.fruits[0].varieties[0].name == "red delicious");
      expect(parsed.fruits[0].varieties[1].name == "granny smith");
      expect(parsed.fruits[0].varieties[2].name == "fuji");
      expect(parsed.fruits[1].name == "banana");
      expect(parsed.fruits[1].varieties.size() == 1);
      expect(parsed.fruits[1].varieties[0].name == "cavendish");
      expect(parsed.fruits[2].name == "orange");
      expect(parsed.fruits[2].varieties.size() == 0);
   };

   "write_array_of_tables_single_element"_test = [] {
      // Single element should still use [[]] syntax
      catalog c{};
      c.store_name = "Single";
      c.products = {{"Only", 1}};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      expect(buffer.find("[[products]]") != std::string::npos);
      expect(buffer.find("name = \"Only\"") != std::string::npos);
   };

   "array_of_tables_preserves_order"_test = [] {
      // Verify elements maintain their order through roundtrip
      catalog original{};
      original.store_name = "Ordered";
      original.products = {{"A", 1}, {"B", 2}, {"C", 3}, {"D", 4}, {"E", 5}};

      std::string buffer{};
      expect(not glz::write_toml(original, buffer));

      catalog parsed{};
      expect(not glz::read_toml(parsed, buffer));

      expect(parsed.products.size() == 5);
      for (size_t i = 0; i < 5; ++i) {
         expect(parsed.products[i] == original.products[i]);
      }
   };

   "read_array_of_tables_partial_fields"_test = [] {
      // Some entries have all fields, some have partial
      std::string input = R"([[products]]
name = "Full"
sku = 100

[[products]]
name = "NameOnly"

[[products]]
sku = 200
)";

      simple_catalog c{};
      expect(not glz::read_toml(c, input));

      expect(c.products.size() == 3);
      expect(c.products[0].name == "Full");
      expect(c.products[0].sku == 100);
      expect(c.products[1].name == "NameOnly");
      expect(c.products[1].sku == 0); // Default
      expect(c.products[2].name == ""); // Default
      expect(c.products[2].sku == 200);
   };

   "array_of_tables_mixed_with_scalars_and_tables"_test = [] {
      // Test struct with scalar, nested table, AND array of tables
      mixed_container original{};
      original.title = "Mixed";
      original.inner = {42, "nested_value"};
      original.items = {{"Item1", 1}, {"Item2", 2}};

      std::string buffer{};
      expect(not glz::write_toml(original, buffer));

      // Scalars should come first, then [inner], then [[items]]
      auto title_pos = buffer.find("title");
      auto inner_pos = buffer.find("[inner]");
      auto items_pos = buffer.find("[[items]]");

      expect(title_pos != std::string::npos);
      expect(inner_pos != std::string::npos);
      expect(items_pos != std::string::npos);
      expect(title_pos < inner_pos);
      expect(inner_pos < items_pos);
   };
};

// Struct for inline_table wrapper tests
struct inline_product
{
   std::string name{};
   int sku{};

   bool operator==(const inline_product&) const = default;
};

template <>
struct glz::meta<inline_product>
{
   using T = inline_product;
   static constexpr auto value = object(&T::name, &T::sku);
};

struct inline_catalog
{
   std::string store_name{};
   std::vector<inline_product> products{};
};

template <>
struct glz::meta<inline_catalog>
{
   using T = inline_catalog;
   // Use inline_table wrapper to force inline syntax instead of [[products]]
   static constexpr auto value = object(&T::store_name, "products", glz::inline_table<&T::products>);
};

struct mixed_inline_and_aot_container
{
   std::string title{};
   std::vector<inline_product> inline_items{}; // Will use inline_table
   std::vector<product> aot_items{}; // Will use array-of-tables
};

template <>
struct glz::meta<mixed_inline_and_aot_container>
{
   using T = mixed_inline_and_aot_container;
   static constexpr auto value = object(&T::title, "inline_items", glz::inline_table<&T::inline_items>, // Inline syntax
                                        &T::aot_items // Array-of-tables syntax
   );
};

suite inline_table_tests = [] {
   "write_inline_table_basic"_test = [] {
      inline_catalog c{};
      c.store_name = "Hardware Store";
      c.products = {{"Hammer", 100}, {"Nail", 200}};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      // Should use inline table syntax, not [[products]]
      expect(buffer.find("[[products]]") == std::string::npos) << "Should not use array-of-tables syntax";
      expect(buffer.find("products = [{") != std::string::npos) << "Should use inline table syntax";
      expect(buffer.find("name = \"Hammer\"") != std::string::npos);
      expect(buffer.find("sku = 100") != std::string::npos);
   };

   "write_inline_table_empty"_test = [] {
      inline_catalog c{};
      c.store_name = "Empty Store";
      c.products = {};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      expect(buffer.find("products = []") != std::string::npos) << "Empty inline array";
   };

   "write_inline_table_single_element"_test = [] {
      inline_catalog c{};
      c.store_name = "Single Item Store";
      c.products = {{"Widget", 42}};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      expect(buffer.find("[[products]]") == std::string::npos);
      expect(buffer.find("products = [{name = \"Widget\", sku = 42}]") != std::string::npos);
   };

   "write_inline_table_multiple_elements"_test = [] {
      inline_catalog c{};
      c.store_name = "Multi Store";
      c.products = {{"A", 1}, {"B", 2}, {"C", 3}};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      // All elements should be on the same line with inline table format
      expect(buffer.find("}, {") != std::string::npos) << "Elements separated by comma-brace";
      expect(buffer.find("[[products]]") == std::string::npos);
   };

   "mixed_inline_and_array_of_tables"_test = [] {
      // Test that inline_table and regular array-of-tables can coexist
      mixed_inline_and_aot_container c{};
      c.title = "Mixed Container";
      c.inline_items = {{"Inline1", 10}, {"Inline2", 20}};
      c.aot_items = {{"AOT1", 100}, {"AOT2", 200}};

      std::string buffer{};
      expect(not glz::write_toml(c, buffer));

      // inline_items should use inline syntax
      expect(buffer.find("inline_items = [{") != std::string::npos) << "Inline items should use inline syntax";
      expect(buffer.find("[[inline_items]]") == std::string::npos) << "Inline items should NOT use [[]] syntax";

      // aot_items should use array-of-tables syntax
      expect(buffer.find("[[aot_items]]") != std::string::npos) << "AOT items should use [[]] syntax";
   };

   "write_with_toml_opts_inline"_test = [] {
      // Test using toml_opts with inline_arrays to force inline arrays globally
      catalog c{};
      c.store_name = "Hardware Store";
      c.products = {{"Hammer", 100}, {"Nail", 200}};

      std::string buffer{};
      expect(not glz::write<glz::toml_opts{true}>(c, buffer));

      // Should use inline syntax, not array-of-tables
      expect(buffer.find("[[products]]") == std::string::npos) << "Should not use [[]] syntax";
      expect(buffer.find("products = [{") != std::string::npos) << "Should use inline array syntax";
   };

   "write_toml_vs_toml_opts_inline_comparison"_test = [] {
      // Compare default write_toml (array-of-tables) vs toml_opts{true}
      catalog c{};
      c.store_name = "Test";
      c.products = {{"A", 1}};

      std::string aot_buffer{};
      std::string inline_buffer{};

      expect(not glz::write_toml(c, aot_buffer));
      expect(not glz::write<glz::toml_opts{true}>(c, inline_buffer));

      // Default uses array-of-tables
      expect(aot_buffer.find("[[products]]") != std::string::npos);
      expect(aot_buffer.find("products = [") == std::string::npos);

      // Inline uses inline arrays
      expect(inline_buffer.find("[[products]]") == std::string::npos);
      expect(inline_buffer.find("products = [{") != std::string::npos);
   };

   "toml_opts_as_constexpr"_test = [] {
      // Users can create their own named constants
      catalog c{};
      c.store_name = "Named";
      c.products = {{"Y", 99}};

      std::string buffer{};
      constexpr glz::toml_opts inline_opts{true};
      expect(not glz::write<inline_opts>(c, buffer));

      expect(buffer.find("[[products]]") == std::string::npos);
      expect(buffer.find("products = [{") != std::string::npos);
   };
};

int main() { return 0; }
