#pragma once

#include <string>
#include <vector>
#include <functional>
#include <chrono>
#include <iostream>

// Simple test result
struct TestResult {
    std::string name;
    bool passed;
    std::string error_message;
    int64_t duration_ms;
};

// Test case definition
struct TestCase {
    std::string name;
    std::function<bool(std::string&)> func;  // Returns true if passed, error in string
};

// Test runner
class TestHarness {
public:
    void AddTest(const std::string& name, std::function<bool(std::string&)> func);

    // Run all tests or filter by name
    std::vector<TestResult> Run(const std::string& filter = "");

    // Output results as JSON
    void WriteJsonReport(const std::vector<TestResult>& results, const std::string& path);

    // Print results to console
    void PrintResults(const std::vector<TestResult>& results);

private:
    std::vector<TestCase> m_tests;
};

// Assertion macros
#define EXPECT_TRUE(cond) \
    do { \
        if (!(cond)) { \
            error_msg = std::string(__FILE__) + ":" + std::to_string(__LINE__) + \
                        ": EXPECT_TRUE(" #cond ") failed"; \
            return false; \
        } \
    } while(0)

#define EXPECT_FALSE(cond) \
    do { \
        if (cond) { \
            error_msg = std::string(__FILE__) + ":" + std::to_string(__LINE__) + \
                        ": EXPECT_FALSE(" #cond ") failed"; \
            return false; \
        } \
    } while(0)

#define EXPECT_EQ(a, b) \
    do { \
        if ((a) != (b)) { \
            error_msg = std::string(__FILE__) + ":" + std::to_string(__LINE__) + \
                        ": EXPECT_EQ failed: " + std::to_string(a) + " != " + std::to_string(b); \
            return false; \
        } \
    } while(0)

#define EXPECT_NE(a, b) \
    do { \
        if ((a) == (b)) { \
            error_msg = std::string(__FILE__) + ":" + std::to_string(__LINE__) + \
                        ": EXPECT_NE failed: values are equal"; \
            return false; \
        } \
    } while(0)

#define EXPECT_CONTAINS(haystack, needle) \
    do { \
        if ((haystack).find(needle) == std::string::npos) { \
            error_msg = std::string(__FILE__) + ":" + std::to_string(__LINE__) + \
                        ": EXPECT_CONTAINS failed: '" + (haystack) + "' does not contain '" + (needle) + "'"; \
            return false; \
        } \
    } while(0)
