// SPDX-License-Identifier: Apache-2.0
// Copyright 2025 C++ Best Practices Example
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @file test_resource_manager.cpp
 * @brief Simple test suite for ResourceManager demonstrating testing best practices
 * @author Generated Example
 * @date 2025
 */

#include "resource_manager.hpp"
#include <iostream>
#include <cassert>
#include <stdexcept>

namespace test {

/**
 * @brief Simple test framework for demonstration
 */
class TestRunner {
private:
    int tests_run_ = 0;
    int tests_passed_ = 0;
    
public:
    template<typename TestFunc>
    void run_test(const std::string& test_name, TestFunc&& test) {
        ++tests_run_;
        try {
            test();
            ++tests_passed_;
            std::cout << "✅ " << test_name << " PASSED\n";
        } catch (const std::exception& e) {
            std::cout << "❌ " << test_name << " FAILED: " << e.what() << "\n";
        } catch (...) {
            std::cout << "❌ " << test_name << " FAILED: Unknown exception\n";
        }
    }
    
    void print_summary() const {
        std::cout << "\n=== Test Summary ===\n";
        std::cout << "Tests run: " << tests_run_ << "\n";
        std::cout << "Tests passed: " << tests_passed_ << "\n";
        std::cout << "Tests failed: " << (tests_run_ - tests_passed_) << "\n";
        
        if (tests_passed_ == tests_run_) {
            std::cout << "🎉 All tests passed!\n";
        } else {
            std::cout << "⚠️  Some tests failed!\n";
        }
    }
    
    bool all_passed() const {
        return tests_passed_ == tests_run_;
    }
};

// Test helper macros
#define ASSERT_TRUE(condition) \
    if (!(condition)) { \
        throw std::runtime_error("Assertion failed: " #condition); \
    }

#define ASSERT_FALSE(condition) \
    if (condition) { \
        throw std::runtime_error("Assertion failed: !(" #condition ")"); \
    }

#define ASSERT_EQ(expected, actual) \
    if ((expected) != (actual)) { \
        throw std::runtime_error("Assertion failed: " #expected " == " #actual); \
    }

#define ASSERT_THROWS(exception_type, expression) \
    { \
        bool threw = false; \
        try { \
            expression; \
        } catch (const exception_type&) { \
            threw = true; \
        } \
        if (!threw) { \
            throw std::runtime_error("Expected exception " #exception_type " was not thrown"); \
        } \
    }

/**
 * @brief Test basic construction and properties
 */
void test_basic_construction() {
    using namespace best_practices;
    
    auto manager = make_resource_manager<int>("TestManager");
    
    ASSERT_EQ("TestManager", manager->getName());
    ASSERT_EQ(0u, manager->size());
    ASSERT_TRUE(manager->empty());
}

/**
 * @brief Test construction with invalid parameters
 */
void test_invalid_construction() {
    using namespace best_practices;
    
    ASSERT_THROWS(std::invalid_argument, ResourceManager<int>(""));
}

/**
 * @brief Test adding elements
 */
void test_adding_elements() {
    using namespace best_practices;
    
    auto manager = make_resource_manager<int>("TestManager");
    
    manager->push_back(42);
    manager->push_back(24);
    manager->emplace_back(100);
    
    ASSERT_EQ(3u, manager->size());
    ASSERT_FALSE(manager->empty());
    ASSERT_EQ(42, manager->at(0));
    ASSERT_EQ(24, manager->at(1));
    ASSERT_EQ(100, manager->at(2));
}

/**
 * @brief Test bounds checking
 */
void test_bounds_checking() {
    using namespace best_practices;
    
    auto manager = make_resource_manager<int>("TestManager");
    manager->push_back(42);
    
    // Valid access
    ASSERT_EQ(42, manager->at(0));
    
    // Invalid access should throw
    ASSERT_THROWS(std::out_of_range, manager->at(1));
    ASSERT_THROWS(std::out_of_range, manager->at(100));
}

/**
 * @brief Test copy semantics
 */
void test_copy_semantics() {
    using namespace best_practices;
    
    auto original = make_resource_manager<int>("Original");
    original->push_back(1);
    original->push_back(2);
    original->push_back(3);
    
    // Copy construction
    auto copy = std::make_unique<ResourceManager<int>>(*original);
    
    ASSERT_EQ(original->getName(), copy->getName());
    ASSERT_EQ(original->size(), copy->size());
    
    for (std::size_t i = 0; i < original->size(); ++i) {
        ASSERT_EQ(original->at(i), copy->at(i));
    }
    
    // Modify original - copy should be unaffected
    original->push_back(4);
    ASSERT_EQ(4u, original->size());
    ASSERT_EQ(3u, copy->size());
}

/**
 * @brief Test move semantics
 */
void test_move_semantics() {
    using namespace best_practices;
    
    auto original = make_resource_manager<int>("Original");
    original->push_back(1);
    original->push_back(2);
    
    const auto original_size = original->size();
    const auto original_name = original->getName();
    
    // Move construction
    auto moved = std::make_unique<ResourceManager<int>>(std::move(*original));
    
    ASSERT_EQ(original_name, moved->getName());
    ASSERT_EQ(original_size, moved->size());
    ASSERT_EQ(1, moved->at(0));
    ASSERT_EQ(2, moved->at(1));
}

/**
 * @brief Test iterator support
 */
void test_iterators() {
    using namespace best_practices;
    
    auto manager = make_resource_manager<int>("TestManager");
    std::vector<int> test_data = {1, 2, 3, 4, 5};
    
    for (const auto& value : test_data) {
        manager->push_back(value);
    }
    
    // Test range-based for loop
    std::size_t index = 0;
    for (const auto& value : *manager) {
        ASSERT_EQ(test_data[index], value);
        ++index;
    }
    
    ASSERT_EQ(test_data.size(), index);
}

/**
 * @brief Test functional operations
 */
void test_functional_operations() {
    using namespace best_practices;
    
    auto manager = make_resource_manager<int>("TestManager");
    for (int i = 1; i <= 10; ++i) {
        manager->push_back(i);
    }
    
    // Test filter
    auto even_numbers = manager->filter([](int x) { return x % 2 == 0; });
    ASSERT_EQ(5u, even_numbers.size());
    ASSERT_EQ(2, even_numbers[0]);
    ASSERT_EQ(10, even_numbers[4]);
    
    // Test transform
    auto doubled = manager->transform([](int x) { return x * 2; });
    ASSERT_EQ(10u, doubled.size());
    ASSERT_EQ(2, doubled[0]);
    ASSERT_EQ(20, doubled[9]);
}

/**
 * @brief Test string specialization
 */
void test_string_specialization() {
    using namespace best_practices;
    
    auto manager = make_resource_manager<std::string>("StringManager");
    
    manager->push_back("Hello");
    manager->push_back("World");
    manager->emplace_back("C++");
    
    ASSERT_EQ(3u, manager->size());
    ASSERT_EQ("Hello", manager->at(0));
    ASSERT_EQ("World", manager->at(1));
    ASSERT_EQ("C++", manager->at(2));
    
    // Test transform with strings
    auto lengths = manager->transform([](const std::string& s) { return s.length(); });
    ASSERT_EQ(3u, lengths.size());
    ASSERT_EQ(5u, lengths[0]); // "Hello"
    ASSERT_EQ(5u, lengths[1]); // "World"
    ASSERT_EQ(3u, lengths[2]); // "C++"
}

} // namespace test

/**
 * @brief Main test runner
 */
int main() {
    std::cout << "=== ResourceManager Test Suite ===\n\n";
    
    test::TestRunner runner;
    
    runner.run_test("Basic Construction", test::test_basic_construction);
    runner.run_test("Invalid Construction", test::test_invalid_construction);
    runner.run_test("Adding Elements", test::test_adding_elements);
    runner.run_test("Bounds Checking", test::test_bounds_checking);
    runner.run_test("Copy Semantics", test::test_copy_semantics);
    runner.run_test("Move Semantics", test::test_move_semantics);
    runner.run_test("Iterators", test::test_iterators);
    runner.run_test("Functional Operations", test::test_functional_operations);
    runner.run_test("String Specialization", test::test_string_specialization);
    
    runner.print_summary();
    
    return runner.all_passed() ? 0 : 1;
}