#ifndef DROPSHELL_ASSERT_HPP
#define DROPSHELL_ASSERT_HPP

#include <iostream>
#include <string_view>
#include <cstdlib> // For std::exit and EXIT_FAILURE

namespace ds {

struct SourceLocation {
    const char* file_name;
    int line;
    const char* function_name;
};

// Helper macro to create a SourceLocation with current context
#define DS_CURRENT_LOCATION ds::SourceLocation{__FILE__, __LINE__, __func__}

[[noreturn]] inline void assert_fail(
    const char* expression,
    const SourceLocation& location,
    const char* message = nullptr) {
    
    std::cerr << "\033[1;31mAssertion failed!\033[0m\n"
              << "Expression: \033[1;33m" << expression << "\033[0m\n"
              << "Location:   \033[1;36m" << location.file_name << ":" 
                                           << location.line << "\033[0m\n"
              << "Function:   \033[1;36m" << location.function_name << "\033[0m\n";
              
    if (message) {
        std::cerr << "Message:    \033[1;37m" << message << "\033[0m\n";
    }
    
    std::cerr << std::endl;
    
    // Exit the program without creating a core dump
    std::exit(EXIT_FAILURE);
}

} // namespace ds

// Standard assertion
#define ASSERT(condition) \
    do { \
        if (!(condition)) { \
            ds::assert_fail(#condition, DS_CURRENT_LOCATION); \
        } \
    } while (false)
    
// Assertion with custom message
#define ASSERT_MSG(condition, message) \
    do { \
        if (!(condition)) { \
            ds::assert_fail(#condition, DS_CURRENT_LOCATION, message); \
        } \
    } while (false)

#endif // DROPSHELL_ASSERT_HPP
