
#include "fl/stl/vector.h"
#include "fl/stl/array.h"
#include "fl/stl/new.h"
#include "test.h"
#include "fl/stl/span.h"
#include "fl/stl/allocator.h"

FL_TEST_FILE(FL_FILEPATH) {


FL_TEST_CASE("fl::span explicit conversions work correctly") {
    FL_SUBCASE("fl::vector to fl::span conversions") {
        // Test const fl::vector -> fl::span<const T>
        fl::vector<int> vec = {1, 2, 3, 4, 5};
        
        // ✅ These explicit conversions should work
        fl::span<const int> const_span(vec);
        FL_CHECK(const_span.size() == 5);
        FL_CHECK(const_span[0] == 1);
        FL_CHECK(const_span[4] == 5);
        
        // ✅ Mutable conversion should work
        fl::span<int> mutable_span(vec);
        FL_CHECK(mutable_span.size() == 5);
        mutable_span[0] = 10;
        FL_CHECK(vec[0] == 10);  // Verify it's a view, not a copy
    }
    
    FL_SUBCASE("fl::array to fl::span conversions") {
        fl::array<int, 4> arr = {10, 20, 30, 40};
        
        // ✅ These explicit conversions should work
        fl::span<const int> const_span(arr);
        FL_CHECK(const_span.size() == 4);
        FL_CHECK(const_span[0] == 10);
        FL_CHECK(const_span[3] == 40);
        
        // ✅ Mutable conversion should work
        fl::span<int> mutable_span(arr);
        FL_CHECK(mutable_span.size() == 4);
        mutable_span[0] = 100;
        FL_CHECK(arr[0] == 100);  // Verify it's a view
    }
    
    FL_SUBCASE("C-style array to fl::span conversions") {
        int c_array[] = {5, 10, 15, 20};
        
        // ✅ These explicit conversions should work
        fl::span<const int> const_span(c_array);
        FL_CHECK(const_span.size() == 4);
        FL_CHECK(const_span[0] == 5);
        FL_CHECK(const_span[3] == 20);
        
        // ✅ Mutable conversion should work
        fl::span<int> mutable_span(c_array);
        FL_CHECK(mutable_span.size() == 4);
        mutable_span[0] = 50;
        FL_CHECK(c_array[0] == 50);  // Verify it's a view
    }
    
    FL_SUBCASE("const array to const span") {
        const int const_array[] = {100, 200, 300};
        
        // ✅ Const array to const span should work
        fl::span<const int> const_span(const_array);
        FL_CHECK(const_span.size() == 3);
        FL_CHECK(const_span[0] == 100);
        FL_CHECK(const_span[2] == 300);
    }
}

FL_TEST_CASE("fl::span non-template function conversions work") {
    // These tests show that non-template functions CAN accept containers
    // via implicit conversion through our constructors
    
    auto process_const_span = [](fl::span<const int> data) -> int {
        int sum = 0;
        for (const auto& item : data) {
            sum += item;
        }
        return sum;
    };
    
    auto modify_span = [](fl::span<int> data) {
        for (auto& item : data) {
            item += 1;
        }
    };
    
    FL_SUBCASE("fl::vector implicit conversion to non-template function") {
        fl::vector<int> vec = {1, 2, 3, 4, 5};
        
        // ✅ This should work - implicit conversion to function parameter
        int result = process_const_span(vec);
        FL_CHECK(result == 15);
        
        // ✅ Mutable function should work too
        modify_span(vec);
        FL_CHECK(vec[0] == 2);
        FL_CHECK(vec[4] == 6);
    }
    
    FL_SUBCASE("fl::array implicit conversion to non-template function") {
        fl::array<int, 3> arr = {10, 20, 30};
        
        // ✅ This should work
        int result = process_const_span(arr);
        FL_CHECK(result == 60);
        
        // ✅ Mutable function should work
        modify_span(arr);
        FL_CHECK(arr[0] == 11);
        FL_CHECK(arr[2] == 31);
    }
    
    FL_SUBCASE("C-style array implicit conversion to non-template function") {
        int c_array[] = {7, 14, 21};
        
        // ✅ This should work
        int result = process_const_span(c_array);
        FL_CHECK(result == 42);
        
        // ✅ Mutable function should work
        modify_span(c_array);
        FL_CHECK(c_array[0] == 8);
        FL_CHECK(c_array[2] == 22);
    }
}

// P2447R6 initializer_list constructor is deleted because the backing array
// is always a temporary, making stored spans dangle.  See span.h.

FL_TEST_CASE("fl::span limitations - template argument deduction") {
    // This test documents what DOESN'T work due to C++ language limitations
    
    FL_SUBCASE("template functions cannot deduce from implicit conversions") {
        fl::vector<int> vec = {1, 2, 3};
        
        // ❌ This would NOT work (commented out to avoid compilation errors):
        // template<typename T> void template_func(fl::span<T> data) { ... }
        // template_func(vec);  // Error: template argument deduction fails
        
        // ✅ This DOES work with explicit template parameters:
        auto template_func = [](fl::span<int> data) -> int {
            int sum = 0;
            for (const auto& item : data) {
                sum += static_cast<int>(item);
            }
            return sum;
        };
        
        int result = template_func(fl::span<int>(vec));  // Explicit conversion
        FL_CHECK(result == 6);
        
        // 📝 This is correct C++ behavior - template argument deduction only 
        // considers exact type matches, not constructor conversions
    }
} 

} // FL_TEST_FILE
