#pragma once

#include <string_view>
#include <chrono>
#include <memory>
#include <vector>
#include <unordered_map>

namespace PerformanceUtils {
    
    // C++23: std::expected-like error handling
    template<typename T, typename E>
    class Expected {
    private:
        union {
            T value_;
            E error_;
        };
        bool has_value_;
        
    public:
        Expected(T&& value) : value_(std::move(value)), has_value_(true) {}
        Expected(const E& error) : error_(error), has_value_(false) {}
        
        bool has_value() const noexcept { return has_value_; }
        const T& value() const { return value_; }
        const E& error() const { return error_; }
        
        T&& move_value() { return std::move(value_); }
    };
    
    // C++23: std::optional with better performance
    template<typename T>
    class FastOptional {
    private:
        alignas(T) char storage_[sizeof(T)];
        bool has_value_;
        
    public:
        FastOptional() : has_value_(false) {}
        
        template<typename... Args>
        FastOptional(Args&&... args) : has_value_(true) {
            new(storage_) T(std::forward<Args>(args)...);
        }
        
        ~FastOptional() {
            if (has_value_) {
                reinterpret_cast<T*>(storage_)->~T();
            }
        }
        
        bool has_value() const noexcept { return has_value_; }
        
        T& value() { return *reinterpret_cast<T*>(storage_); }
        const T& value() const { return *reinterpret_cast<const T*>(storage_); }
    };
    
    // String interning for better memory usage
    class StringInterner {
    private:
        std::unordered_map<std::string_view, std::string> interned_strings_;
        
    public:
        std::string_view intern(std::string_view str) {
            auto it = interned_strings_.find(str);
            if (it != interned_strings_.end()) {
                return it->second;
            }
            
            auto [new_it, inserted] = interned_strings_.emplace(str, std::string(str));
            return new_it->second;
        }
    };
    
    // Performance timer
    class Timer {
    private:
        std::chrono::high_resolution_clock::time_point start_;
        
    public:
        Timer() : start_(std::chrono::high_resolution_clock::now()) {}
        
        auto elapsed() const {
            return std::chrono::high_resolution_clock::now() - start_;
        }
        
        auto elapsed_ms() const {
            return std::chrono::duration_cast<std::chrono::milliseconds>(elapsed()).count();
        }
    };
    
    // Memory pool for frequent allocations
    template<typename T>
    class MemoryPool {
    private:
        std::vector<std::unique_ptr<T[]>> blocks_;
        std::vector<T*> free_list_;
        size_t block_size_;
        size_t current_block_;
        size_t current_index_;
        
    public:
        MemoryPool(size_t block_size = 1024) 
            : block_size_(block_size), current_block_(0), current_index_(0) {
            allocate_block();
        }
        
        T* allocate() {
            if (!free_list_.empty()) {
                T* ptr = free_list_.back();
                free_list_.pop_back();
                return ptr;
            }
            
            if (current_index_ >= block_size_) {
                allocate_block();
            }
            
            return &blocks_[current_block_][current_index_++];
        }
        
        void deallocate(T* ptr) {
            free_list_.push_back(ptr);
        }
        
    private:
        void allocate_block() {
            blocks_.emplace_back(std::make_unique<T[]>(block_size_));
            current_block_ = blocks_.size() - 1;
            current_index_ = 0;
        }
    };
}
