#include "format.hpp"
#include "panic.hpp"
#include "print.hpp"
#include "ranges/enumerate.hpp"
#include "ranges/first.hpp"
#include "ranges/generated.hpp"
#include "tagged_union.hpp"
#include <cstdlib>
#include <iostream>
#include <stdio.h>

#define UTIL_ASSERT_FORMAT
#include "assert.hpp"
#include "ranges/collect.hpp"
#include <map>
#include <ranges>
#include <set>
#include <string_view>
#include <vector>

using namespace std::string_view_literals;
using namespace util::bitflag_operators;

enum class E {
  A = 0x1,
  B = 0x10,
  C = 0x100,
  D = 0x1000,
};

int main(int argc, const char *argv[]) {
  printf("Hello, Alloy!\n");

  const auto a = E::A;
  const auto ab = E::A | E::B;
  const auto all = E::A | E::B | E::C | E::D;

  auto vec = std::vector<int>({1, 2, 3, 4, 5});

  auto range = vec | std::views::filter([](auto &i) { return i % 2; });
  auto infinite_range = util::views::from([] {return 1;}) | std::views::take(5);

  auto map =
      vec | util::views::enumerate | util::views::collect<std::map<int, int>>;

  for (auto &&[i, e] : map) {
    util::println("[{}] {}", i, e);
  }

  auto random = util::views::from([] {
          return "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY"
              [std::rand() %
               std::strlen(
                   "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXY")];
        }) |
        std::views::take(10) | util::views::collect<std::string>;

auto first = random | util::views::first;

util::println("{}", first);
util::println("{}", random);

  for (auto&& i : infinite_range) {
    util::print("{}\n", i);
  }

  const auto set = util::collect<std::set<int>>(range);

  util::print("hello {}\n", "world");

  util::assert_ne("asdf"sv, "nsdf"sv);
  util::panic("asdf {}", 42);
  return 1;
}