#include <iterator>    // For iterator traits
#include <cassert>     // For assert
#include <utility>     // For std::pair, std::make_pair
#include <cstddef>     // For size_t

template <typename EnumType>
class EnumIterator {
public:
    // Standard iterator traits
    using value_type = std::pair<EnumType, const char*>;
    using difference_type = std::ptrdiff_t;
    using pointer = const value_type*;  // Const for safety
    using reference = const value_type&;  // Const for safety
    using iterator_category = std::forward_iterator_tag;

    // Constructor for begin iterator (starts at pos=0)
    EnumIterator(const EnumType* values, const char** names, size_t size, size_t pos = 0)
        : values_(values), names_(names), size_(size), pos_(pos) {}

    // Static factory for end iterator
    static EnumIterator end(const EnumType* values, const char** names, size_t size) {
        return EnumIterator(values, names, size, size);
    }

    // Pre-increment (advances and returns reference to self)
    EnumIterator& operator++() {
        assert(pos_ < size_ && "Increment past end");
        ++pos_;
        return *this;
    }

    // Post-increment (advances but returns copy of old state)
    EnumIterator operator++(int) {
        EnumIterator temp = *this;
        ++(*this);
        return temp;
    }

    // Equality and inequality
    bool operator==(const EnumIterator& other) const {
        return pos_ == other.pos_ && values_ == other.values_ && names_ == other.names_;
    }

    bool operator!=(const EnumIterator& other) const {
        return !(*this == other);
    }

    // Dereference (returns a pair)
    value_type operator*() const {
        assert(pos_ < size_ && "Dereference past end");
        return std::make_pair(values_[pos_], names_[pos_]);
    }

    // Arrow operator (for -> syntax)
    pointer operator->() const {
        assert(pos_ < size_ && "Arrow past end");
        current_ = std::make_pair(values_[pos_], names_[pos_]);
        return &current_;
    }

private:
    const EnumType* values_;
    const char** names_;
    size_t size_;
    size_t pos_;
    mutable value_type current_;  // Mutable cache for operator->
};

// Helper range class for STL compatibility and range-based for loops
template <typename EnumType>
class EnumRange {
public:
    EnumRange(const EnumType* values, const char** names, size_t size)
        : values_(values), names_(names), size_(size) {}

    EnumIterator<EnumType> begin() const {
        return EnumIterator<EnumType>(values_, names_, size_, 0);
    }

    EnumIterator<EnumType> end() const {
        return EnumIterator<EnumType>::end(values_, names_, size_);
    }

private:
    const EnumType* values_;
    const char** names_;
    size_t size_;
};


#include <iostream>
#include <algorithm>   // For std::find_if, std::transform
#include <vector>      // For std::vector
#include <string>      // For std::string

// (Include the improved EnumIterator and EnumRange from above)

// Example enum
enum class Color { Red = 1, Green = 2, Blue = 4, Yellow = 8 };

int main() {
    // Arrays of enum values and names
    const Color color_values[] = {Color::Red, Color::Green, Color::Blue, Color::Yellow};
    const char* color_names[] = {"Red", "Green", "Blue", "Yellow"};
    const size_t color_count = sizeof(color_values) / sizeof(color_values[0]);

    // Create a range object
    EnumRange<Color> colors(color_values, color_names, color_count);

    // Showcase 1: Range-based for loop (modern and simple)
    std::cout << "Showcase 1: Range-based for loop:\n";
    for (const auto& [value, name] : colors) {
        std::cout << name << " = " << static_cast<int>(value) << "\n";
    }

    // Showcase 2: Manual iteration with pre/post-increment and arrow operator
    std::cout << "\nShowcase 2: Manual iteration:\n";
    auto it = colors.begin();
    while (it != colors.end()) {
        std::cout << it->second << " has value " << static_cast<int>(it->first) << "\n";
        it++;  // Post-increment
    }

    // Showcase 3: Using STL algorithm (std::find_if)
    std::cout << "\nShowcase 3: Finding 'Blue' with std::find_if:\n";
    auto found_it = std::find_if(colors.begin(), colors.end(),
                                 [](const auto& p) { return p.first == Color::Blue; });
    if (found_it != colors.end()) {
        auto [value, name] = *found_it;
        std::cout << "Found: " << name << " = " << static_cast<int>(value) << "\n";
    } else {
        std::cout << "Not found\n";
    }

    // Showcase 4: Collecting into a vector with std::transform
    std::cout << "\nShowcase 4: Collecting names into a vector with std::transform:\n";
    std::vector<std::string> name_list;
    std::transform(colors.begin(), colors.end(), std::back_inserter(name_list),
                   [](const auto& p) { return std::string(p.second); });
    for (const auto& name : name_list) {
        std::cout << "- " << name << "\n";
    }

    return 0;
}
// show me a more realistic example about Iterator