#include "ANSUtilities.h"
#include <iostream>
#include <CkFileAccess.h>
#include <CkAuthGoogle.h>
#include <CkSocket.h>
#include <CkGlobal.h>
#include <CkMailMan.h>
#include <CkEmail.h>
#include <CkMht.h>
#include <vector>
#include <CkBinData.h>
#include <CkStringBuilder.h>
#include <CkStream.h>
#include <fstream>
static bool ansawss3LicenceValid = false;
static std::once_flag ansawss3LicenseOnceFlag;

namespace ANSCENTER
{
    static void VerifyGlobalANSAWSS3License(const std::string& licenseKey) {
        try {
            static const std::vector<std::pair<int, std::string>> licenseChecks = {
                {1000, "ANNHUB-LV"},
                {1001, "DLHUB-LV"},
                {1002, "ODHUB-LV"},
                {1003, "ANSVIS"},
                {1004, "ANSFR"},
                {1005, "ANSOCR"},
                {1006, "ANSALPR"},
                {1007, "ANSCV"},
                {1008, "ANSSRT"}
            };
            ansawss3LicenceValid = false;
            for (const auto& [productId, productName] : licenseChecks) {
                if (ANSCENTER::ANSLicenseHelper::LicenseVerification(licenseKey, productId, productName)) {
                    ansawss3LicenceValid = true;
                    break; // Stop at the first valid license
                }
            }
        }
        catch (const std::exception& e) {
            ansawss3LicenceValid = false;
        }
    }
    
	// Private helper function to extract file name from a path
      // Helper function to extract filename from path
    std::string ANSAWSS3::ExtractFileName(const std::string& filePath) {
        size_t pos = filePath.find_last_of("/\\");
        if (pos != std::string::npos) {
            return filePath.substr(pos + 1);
        }
        return filePath;
    }

    // Helper function to determine content type from file extension
    std::string ANSAWSS3::GetContentType(const std::string& filePath) {
        // Default to application/octet-stream for unknown types
        std::string contentType = "application/octet-stream";

        size_t extPos = filePath.find_last_of('.');
        if (extPos == std::string::npos) {
            return contentType;
        }

        // Extract and convert extension to lowercase
        std::string fileExt = filePath.substr(extPos + 1);
        std::transform(fileExt.begin(), fileExt.end(), fileExt.begin(), ::tolower);

        // Image types
        if (fileExt == "jpg" || fileExt == "jpeg") {
            contentType = "image/jpeg";
        }
        else if (fileExt == "png") {
            contentType = "image/png";
        }
        else if (fileExt == "gif") {
            contentType = "image/gif";
        }
        else if (fileExt == "bmp") {
            contentType = "image/bmp";
        }
        else if (fileExt == "webp") {
            contentType = "image/webp";
        }
        else if (fileExt == "svg") {
            contentType = "image/svg+xml";
        }
        else if (fileExt == "ico") {
            contentType = "image/x-icon";
        }
        // Video types
        else if (fileExt == "mp4") {
            contentType = "video/mp4";
        }
        else if (fileExt == "avi") {
            contentType = "video/x-msvideo";
        }
        else if (fileExt == "mov") {
            contentType = "video/quicktime";
        }
        // Document types
        else if (fileExt == "pdf") {
            contentType = "application/pdf";
        }
        else if (fileExt == "json") {
            contentType = "application/json";
        }
        else if (fileExt == "xml") {
            contentType = "application/xml";
        }
        else if (fileExt == "txt") {
            contentType = "text/plain";
        }

        return contentType;
    }
    
    ANSAWSS3::ANSAWSS3() {
        _unlockCode = "ANSDRC.CB1122026_MEQCIFwO1IFQCG0BhZwsXFO68QUU6mDB5uge4duOsqOJanEyAiAB67ahqnXin4SRy0vIegISgbFlpldmbuS5gbU21GYVqA==";// "ANSDRC.CB1082025_Ax6P3M7F8B3d";//
        _proxyHost = "";
        _proxyPort = 0;
        _proxyUsername = "";
        _proxyPassword = "";
        _bProxy = false;
		_serviceName = "s3";
    }
    ANSAWSS3::~ANSAWSS3() {
        StopRetry();
        std::lock_guard<std::mutex> lk(_poolMutex);
        _pool.clear();  // CkRest destructors handle disconnect
    }

    void ANSAWSS3::StopRetry() {
        _stopRetry = true;
        if (_retryThread.joinable()) {
            _retryThread.join();
        }
        _retryInProgress = false;
    }

    // TryConnect — actual connection attempt (caller must hold _configMutex)
    bool ANSAWSS3::TryConnect(bool& awsPath) {
        auto testConn = CreateConnection();
        if (!testConn) {
            // Fallback: connect directly to baseDomain (MinIO, Ceph, etc.)
            std::string savedFullURL = _fullAWSURL;
            _fullAWSURL = _baseDomain;
            testConn = CreateConnection();
            if (!testConn) {
                _fullAWSURL = savedFullURL;  // restore on failure
                return false;
            }
            awsPath = false;
            _bAwsPath = false;
        }
        else {
            awsPath = true;
            _bAwsPath = true;
        }

        _bConnected = true;

        // Return test connection to pool for reuse
        {
            std::lock_guard<std::mutex> lk(_poolMutex);
            _pool.push_back(std::move(testConn));
        }
        return true;
    }

    void ANSAWSS3::RetryLoop() {
        int attempt = 0;

        while (!_stopRetry) {
            // Wait 3 seconds (in 1-second increments so we can respond to stop quickly)
            for (int i = 0; i < 3 && !_stopRetry; ++i) {
                std::this_thread::sleep_for(std::chrono::seconds(1));
            }
            if (_stopRetry) break;

            attempt++;

            // Quick DNS check — is internet available?
            {
                CkSocket dnsCheck;
                CkString dnsResult;
                if (!dnsCheck.DnsLookup(_fullAWSURL.c_str(), 3000, dnsResult)) {
                    _logger.LogDebug("ANSAWSS3::RetryLoop",
                        "Retry #" + std::to_string(attempt) + " - no internet, retrying in 3s",
                        __FILE__, __LINE__);
                    continue;
                }
            }

            // Internet is available — attempt real connection to validate auth/URL
            {
                std::lock_guard<std::mutex> lk(_configMutex);
                bool awsPath = true;
                if (TryConnect(awsPath)) {
                    _logger.LogDebug("ANSAWSS3::RetryLoop",
                        "Connected successfully after " + std::to_string(attempt) + " retries",
                        __FILE__, __LINE__);
                    _retryInProgress = false;
                    return;
                }
                else {
                    // Internet is available but connection failed (bad auth/URL)
                    // Stop retrying — no point, the parameters are wrong
                    _logger.LogError("ANSAWSS3::RetryLoop",
                        "Internet available but connection failed (check authentication or URL). Stopping retry.",
                        __FILE__, __LINE__);
                    _retryInProgress = false;
                    return;
                }
            }
        }
        _retryInProgress = false;
    }

    // ── Connection pool helpers ──
    std::unique_ptr<S3Connection> ANSAWSS3::CreateConnection() {
        auto conn = std::make_unique<S3Connection>();

        // Connect
        if (!conn->rest.Connect(_fullAWSURL.c_str(), _port, _bTls, _bAutoReconnect)) {
            _logger.LogError("ANSAWSS3::CreateConnection", conn->rest.lastErrorText(), __FILE__, __LINE__);
            return nullptr;
        }

        // Apply proxy if configured
        if (_bProxy) {
            conn->socket.put_HttpProxyHostname(_proxyHost.c_str());
            conn->socket.put_HttpProxyPort(_proxyPort);
            conn->socket.put_HttpProxyUsername(_proxyUsername.c_str());
            conn->socket.put_HttpProxyPassword(_proxyPassword.c_str());
            conn->socket.put_HttpProxyForHttp(_bProxy);
            if (!conn->rest.UseConnection(conn->socket, true)) {
                _logger.LogError("ANSAWSS3::CreateConnection - Proxy error", conn->rest.lastErrorText(), __FILE__, __LINE__);
                return nullptr;
            }
        }

        // Apply auth
        if (_authReady) {
            conn->authAws.put_AccessKey(_accessKey.c_str());
            conn->authAws.put_SecretKey(_secretKey.c_str());
            conn->authAws.put_ServiceName(_serviceName.c_str());
            if (_bucketRegion != "us-east-1") {
                if (!_bucketRegion.empty()) conn->authAws.put_Region(_bucketRegion.c_str());
            }
            if (!conn->rest.SetAuthAws(conn->authAws)) {
                _logger.LogError("ANSAWSS3::CreateConnection - Auth error", conn->rest.lastErrorText(), __FILE__, __LINE__);
                return nullptr;
            }
        }

        return conn;
    }

    std::unique_ptr<S3Connection> ANSAWSS3::AcquireConnection() {
        {
            std::lock_guard<std::mutex> lk(_poolMutex);
            if (!_pool.empty()) {
                auto conn = std::move(_pool.back());
                _pool.pop_back();
                return conn;
            }
        }
        // Pool empty — create a new connection (no lock held during network I/O)
        std::lock_guard<std::mutex> cfgLk(_configMutex);
        return CreateConnection();
    }

    void ANSAWSS3::ReleaseConnection(std::unique_ptr<S3Connection> conn) {
        if (!conn) return;
        std::lock_guard<std::mutex> lk(_poolMutex);
        _pool.push_back(std::move(conn));
    }

    void ANSAWSS3::CheckLicense() {
        // Note: caller (Initialize) already holds _configMutex
        try {
            // Check once globally
            std::call_once(ansawss3LicenseOnceFlag, [this]() {
                VerifyGlobalANSAWSS3License(_licenseKey);
            });
            // Update this instance's local license flag
            _isLicenseValid = ansawss3LicenceValid;
        }
        catch (const std::exception& e) {
            this->_logger.LogFatal("ANSAWSS3::CheckLicense. Error:", e.what(), __FILE__, __LINE__);
        }
    }
    void ANSAWSS3::CheckUnlockCode() {
        // Note: caller (Initialize) already holds _configMutex
        try {
            CkGlobal glob;
            _unlockCode = "ANSDRC.CB1122026_MEQCIFwO1IFQCG0BhZwsXFO68QUU6mDB5uge4duOsqOJanEyAiAB67ahqnXin4SRy0vIegISgbFlpldmbuS5gbU21GYVqA==";// "ANSDRC.CB1082025_Ax6P3M7F8B3d";
            _isUnlockCodeValid = glob.UnlockBundle(_unlockCode.c_str());

            if (!_isUnlockCodeValid) {
                _logger.LogFatal("ANSAWSS3::CheckUnlockCode", glob.lastErrorText(), __FILE__, __LINE__);
                return;
            }

            int status = glob.get_UnlockStatus();
            if (status != 2) {
                _logger.LogDebug("ANSAWSS3::CheckUnlockCode", "Unlocked in trial mode.", __FILE__, __LINE__);
            }
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::CheckUnlockCode", e.what(), __FILE__, __LINE__);
        }
    }
    bool ANSAWSS3::Initialize(const std::string& licenseKey) {
        std::lock_guard<std::mutex> lock(_configMutex);
        try {
            _licenseKey = licenseKey;
            CheckLicense();
            CheckUnlockCode();
            return _isLicenseValid && _isUnlockCodeValid;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::Initialize", e.what(), __FILE__, __LINE__);
            return false;
        }

    }
    bool ANSAWSS3::SetServerProxy(const std::string& proxyHost, int proxyPort,const std::string& proxyUsername,const std::string& proxyPassword) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid) {
            _logger.LogError("ANSAWSS3::SetServerProxy",
                !_isLicenseValid ? "Invalid license" : "Invalid unlock code",
                __FILE__, __LINE__);
            return false;
        }
        std::lock_guard<std::mutex> lock(_configMutex);
        try {
            _proxyHost = proxyHost;
            _proxyPort = proxyPort;
            _proxyUsername = proxyUsername;
            _proxyPassword = proxyPassword;

            // Simplified proxy validation logic
            _bProxy = !proxyHost.empty() && proxyPort > 0;

            // Clear pool so new connections pick up proxy config
            {
                std::lock_guard<std::mutex> lk(_poolMutex);
                _pool.clear();
            }
            return true;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::SetServerProxy", e.what(), __FILE__, __LINE__);
            return false;
        }
    }
    // Returns: 1 = connected, 0 = failed (bad auth/URL), 2 = no internet (background retry started)
    int ANSAWSS3::Connect(const std::string& baseDomain, const std::string& bucketRegion, const std::string& serviceName, int port, bool bTls, bool autoReconnect, bool &awsPath)
    {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid) {
            _logger.LogError("ANSAWSS3::Connect",
                !_isLicenseValid ? "Invalid license" : "Invalid unlock code",
                __FILE__, __LINE__);
            return 0;
        }

        // Stop any existing background retry
        StopRetry();

        std::lock_guard<std::mutex> lock(_configMutex);
        try {
            // Store parameters — strip http:// or https:// from baseDomain
            {
                std::string domain = baseDomain.empty() ? "amazonaws.com" : baseDomain;
                if (domain.rfind("https://", 0) == 0) {
                    domain = domain.substr(8);
                    bTls = true;   // caller said https, honour it
                }
                else if (domain.rfind("http://", 0) == 0) {
                    domain = domain.substr(7);
                }
                // Remove trailing slash if any
                if (!domain.empty() && domain.back() == '/') domain.pop_back();
                _baseDomain = domain;
            }
            _bucketRegion = bucketRegion.empty() ? "us-east-1" : bucketRegion;
            _serviceName = serviceName.empty() ? "s3" : serviceName;
			_fullAWSURL = _serviceName + "." + _bucketRegion + "." + _baseDomain;
            _port = port;
            _bTls = bTls;
            _bAutoReconnect = autoReconnect;

            // Clear pool so new connections use updated config
            {
                std::lock_guard<std::mutex> lk(_poolMutex);
                _pool.clear();
            }

            // Check if internet is available (fast DNS check)
            {
                CkSocket dnsCheck;
                CkString dnsResult;
                if (!dnsCheck.DnsLookup(_fullAWSURL.c_str(), 3000, dnsResult)) {
                    // No internet — start background retry, return immediately
                    _logger.LogDebug("ANSAWSS3::Connect",
                        "No internet available, starting background retry for '" + _fullAWSURL + "'...",
                        __FILE__, __LINE__);

                    _stopRetry = false;
                    _retryInProgress = true;
                    _retryThread = std::thread(&ANSAWSS3::RetryLoop, this);
                    return 2;  // no internet, retrying in background
                }
            }

            // Internet is available — try real connection
            if (TryConnect(awsPath)) {
                return 1;  // connected successfully
            }

            // Internet available but connection failed (bad auth, wrong URL, etc.)
            return 0;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::Connect", e.what(), __FILE__, __LINE__);
            return 0;
        }
    }
    bool ANSAWSS3::SetAuthentication(const std::string& accessKey,const std::string& secretKey) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid) {
            _logger.LogError("ANSAWSS3::SetAuthentication",
                !_isLicenseValid ? "Invalid license" : "Invalid unlock code",
                __FILE__, __LINE__);
            return false;
        }
        std::lock_guard<std::mutex> lock(_configMutex);
        try {
			_accessKey = accessKey;
			_secretKey = secretKey;
            _authReady = true;

            // Clear pool so new connections pick up new credentials
            {
                std::lock_guard<std::mutex> lk(_poolMutex);
                _pool.clear();
            }

            return true;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::SetAuthentication", e.what(), __FILE__, __LINE__);
            return false;
        }
    }
    std::vector<std::string> ANSAWSS3::ListBuckets() {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::ListBuckets",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return {};
        }

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("ListBuckets", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return {};
            }

            // Make request and capture response
            conn->rest.put_Host(_fullAWSURL.c_str());
            CkStringBuilder sbResponse;
            if (!conn->rest.FullRequestNoBodySb("GET", "/", sbResponse)) {
                _logger.LogError("ANSAWSS3::ListBuckets - Request failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return {};
            }

            // Check HTTP status code
            int statusCode = conn->rest.get_ResponseStatusCode();
            if (statusCode != 200) {
                _logger.LogError("ANSAWSS3::ListBuckets - HTTP " + std::to_string(statusCode),
                    sbResponse.getAsString(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return {};
            }

            // Parse XML response
            CkXml xml;
            if (!xml.LoadSb(sbResponse, true)) {
                _logger.LogError("ANSAWSS3::ListBuckets - XML parse error",
                    xml.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return {};
            }

            // Extract bucket names
            std::vector<std::string> bucketList;
            int bucketCount = xml.NumChildrenHavingTag("Buckets|Bucket");

            if (bucketCount > 0) {
                bucketList.reserve(bucketCount);

                for (int i = 0; i < bucketCount; ++i) {
                    xml.put_I(i);
                    const char* name = xml.getChildContent("Buckets|Bucket[i]|Name");

                    // Validate name before adding
                    if (name != nullptr && name[0] != '\0') {
                        bucketList.emplace_back(name);
                    }
                }
            }
            ReleaseConnection(std::move(conn));
            return bucketList;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::ListBuckets", e.what(), __FILE__, __LINE__);
            return {};
        }
    }
    std::vector<std::string> ANSAWSS3::ListBucketObjects(const std::string& bucketName) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::ListBucketObjects",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return {};
        }

        if (bucketName.empty()) {
            _logger.LogError("ANSAWSS3::ListBucketObjects",
                "Bucket name is empty",
                __FILE__, __LINE__);
            return {};
        }

        std::vector<std::string> objectList;

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("ListBucketObjects", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return {};
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            std::string marker = "";
            bool isTruncated = true;
            int pageCount = 0;

            // Loop to handle pagination
            while (isTruncated) {
                pageCount++;

                // Build the request path with marker if available
                std::string basePath = _bAwsPath ? "/" : ("/" + bucketName + "/");
                std::string requestPath = basePath;
                if (!marker.empty()) {
                    requestPath = basePath + "?marker=" + marker;
                }

                CkStringBuilder sbResponse;
                bool success = conn->rest.FullRequestNoBodySb("GET", requestPath.c_str(), sbResponse);

                if (!success) {
                    _logger.LogError("ANSAWSS3::ListBucketObjects - Request failed on page " + std::to_string(pageCount),
                        conn->rest.lastErrorText(), __FILE__, __LINE__);
                    ReleaseConnection(std::move(conn));
                    return objectList; // Return what we have so far
                }

                int statusCode = conn->rest.get_ResponseStatusCode();

                if (statusCode != 200) {
                    std::string errorMsg = "HTTP " + std::to_string(statusCode);
                    std::string response = sbResponse.getAsString();
                    if (!response.empty()) {
                        errorMsg += " - " + response;
                    }
                    _logger.LogError("ANSAWSS3::ListBucketObjects - Page " + std::to_string(pageCount),
                        errorMsg, __FILE__, __LINE__);
                    ReleaseConnection(std::move(conn));
                    return objectList; // Return what we have so far
                }

                // Parse XML response
                CkXml xml;
                bool loadSuccess = xml.LoadSb(sbResponse, true);
                if (!loadSuccess) {
                    _logger.LogError("ANSAWSS3::ListBucketObjects",
                        "Failed to parse XML response on page " + std::to_string(pageCount) + ": " + std::string(xml.lastErrorText()),
                        __FILE__, __LINE__);
                    ReleaseConnection(std::move(conn));
                    return objectList; // Return what we have so far
                }

                // Check if results are truncated (more pages to fetch)
                const char* truncatedStr = xml.getChildContent("IsTruncated");
                isTruncated = (truncatedStr != nullptr && std::string(truncatedStr) == "true");

                // Get the marker for next page
                if (isTruncated) {
                    // First try to get NextMarker
                    const char* nextMarker = xml.getChildContent("NextMarker");
                    if (nextMarker != nullptr && nextMarker[0] != '\0') {
                        marker = std::string(nextMarker);
                    }
                    else {
                        // If NextMarker is not present, use the last Key as marker
                        int count = xml.NumChildrenHavingTag("Contents");
                        if (count > 0) {
                            xml.put_I(count - 1); // Last element
                            const char* lastKey = xml.getChildContent("Contents[i]|Key");
                            if (lastKey != nullptr && lastKey[0] != '\0') {
                                marker = std::string(lastKey);
                            }
                            else {
                                isTruncated = false;
                            }
                        }
                        else {
                            isTruncated = false;
                        }
                    }
                }

                // Iterate through all Contents elements in this page
                int count = xml.NumChildrenHavingTag("Contents");

                for (int i = 0; i < count; i++) {
                    xml.put_I(i);
                    const char* key = xml.getChildContent("Contents[i]|Key");

                    if (key != nullptr && key[0] != '\0') {
                        objectList.emplace_back(key);
                    }
                }

                _logger.LogDebug("ANSAWSS3::ListBucketObjects",
                    "Page " + std::to_string(pageCount) + ": Retrieved " + std::to_string(count) +
                    " objects. Total so far: " + std::to_string(objectList.size()),
                    __FILE__, __LINE__);
            }

            _logger.LogDebug("ANSAWSS3::ListBucketObjects",
                "Successfully listed " + std::to_string(objectList.size()) +
                " objects in bucket: " + bucketName + " (" + std::to_string(pageCount) + " pages)",
                __FILE__, __LINE__);

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::ListBucketObjects",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
            objectList.clear(); // Ensure we return empty list on exception
        }

        return objectList;
    }
    std::vector<std::string> ANSAWSS3::ListBucketObjectsWithPrefix(const std::string& bucketName, const std::string& prefix) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::ListBucketObjectsWithPrefix",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return {};
        }

        if (bucketName.empty()) {
            _logger.LogError("ANSAWSS3::ListBucketObjectsWithPrefix",
                "Bucket name is empty",
                __FILE__, __LINE__);
            return {};
        }

        // prefix can be empty to list all objects
        std::vector<std::string> objectList;

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("ListBucketObjectsWithPrefix", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return {};
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            std::string marker = "";
            bool isTruncated = true;
            int pageCount = 0;

            // Loop to handle pagination
            while (isTruncated) {
                pageCount++;

                // Build the request path with prefix and marker
                std::string basePath = _bAwsPath ? "/" : ("/" + bucketName + "/");
                std::string requestPath = basePath;
                bool hasParams = false;

                // Add prefix parameter if provided
                if (!prefix.empty()) {
                    requestPath += "?prefix=" + prefix;
                    hasParams = true;
                }

                // Add marker parameter if available
                if (!marker.empty()) {
                    if (hasParams) {
                        requestPath += "&marker=" + marker;
                    }
                    else {
                        requestPath += "?marker=" + marker;
                        hasParams = true;
                    }
                }

                CkStringBuilder sbResponse;
                bool success = conn->rest.FullRequestNoBodySb("GET", requestPath.c_str(), sbResponse);

                if (!success) {
                    _logger.LogError("ANSAWSS3::ListBucketObjectsWithPrefix - Request failed on page " + std::to_string(pageCount),
                        conn->rest.lastErrorText(), __FILE__, __LINE__);
                    ReleaseConnection(std::move(conn));
                    return objectList; // Return what we have so far
                }

                int statusCode = conn->rest.get_ResponseStatusCode();

                if (statusCode != 200) {
                    std::string errorMsg = "HTTP " + std::to_string(statusCode);
                    std::string response = sbResponse.getAsString();
                    if (!response.empty()) {
                        errorMsg += " - " + response;
                    }
                    _logger.LogError("ANSAWSS3::ListBucketObjectsWithPrefix - Page " + std::to_string(pageCount),
                        errorMsg, __FILE__, __LINE__);
                    ReleaseConnection(std::move(conn));
                    return objectList; // Return what we have so far
                }

                // Parse XML response
                CkXml xml;
                bool loadSuccess = xml.LoadSb(sbResponse, true);
                if (!loadSuccess) {
                    _logger.LogError("ANSAWSS3::ListBucketObjectsWithPrefix",
                        "Failed to parse XML response on page " + std::to_string(pageCount) + ": " + std::string(xml.lastErrorText()),
                        __FILE__, __LINE__);
                    ReleaseConnection(std::move(conn));
                    return objectList; // Return what we have so far
                }

                // Check if results are truncated (more pages to fetch)
                const char* truncatedStr = xml.getChildContent("IsTruncated");
                isTruncated = (truncatedStr != nullptr && std::string(truncatedStr) == "true");

                // Get the marker for next page
                if (isTruncated) {
                    // First try to get NextMarker
                    const char* nextMarker = xml.getChildContent("NextMarker");
                    if (nextMarker != nullptr && nextMarker[0] != '\0') {
                        marker = std::string(nextMarker);
                    }
                    else {
                        // If NextMarker is not present, use the last Key as marker
                        int count = xml.NumChildrenHavingTag("Contents");
                        if (count > 0) {
                            xml.put_I(count - 1); // Last element
                            const char* lastKey = xml.getChildContent("Contents[i]|Key");
                            if (lastKey != nullptr && lastKey[0] != '\0') {
                                marker = std::string(lastKey);
                            }
                            else {
                                isTruncated = false;
                            }
                        }
                        else {
                            isTruncated = false;
                        }
                    }
                }

                // Iterate through all Contents elements in this page
                int count = xml.NumChildrenHavingTag("Contents");

                for (int i = 0; i < count; i++) {
                    xml.put_I(i);
                    const char* key = xml.getChildContent("Contents[i]|Key");

                    if (key != nullptr && key[0] != '\0') {
                        objectList.emplace_back(key);
                    }
                }

                std::string prefixInfo = prefix.empty() ? "all objects" : "prefix '" + prefix + "'";
                _logger.LogDebug("ANSAWSS3::ListBucketObjectsWithPrefix",
                    "Page " + std::to_string(pageCount) + ": Retrieved " + std::to_string(count) +
                    " objects for " + prefixInfo + ". Total so far: " + std::to_string(objectList.size()),
                    __FILE__, __LINE__);
            }

            std::string prefixInfo = prefix.empty() ? "" : " with prefix '" + prefix + "'";
            _logger.LogDebug("ANSAWSS3::ListBucketObjectsWithPrefix",
                "Successfully listed " + std::to_string(objectList.size()) +
                " objects in bucket: " + bucketName + prefixInfo + " (" + std::to_string(pageCount) + " pages)",
                __FILE__, __LINE__);

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::ListBucketObjectsWithPrefix",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
            objectList.clear(); // Ensure we return empty list on exception
        }

        return objectList;
    }
    
    bool ANSAWSS3::CreateBucket(const std::string& bucketName) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::CreateBucket",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        // Validate input parameters
        if (bucketName.empty()) {
            _logger.LogError("ANSAWSS3::CreateBucket",
                "Bucket name cannot be empty",
                __FILE__, __LINE__);
            return false;
        }

        bool createSuccess = false;

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("CreateBucket", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Build global endpoint
            std::string globalEndpoint = _serviceName + "." + _baseDomain;
            CkStringBuilder sbBucketRegion;
            sbBucketRegion.Append(_bucketRegion.c_str());

            // We only need to specify the LocationConstraint if the bucket's region is NOT us-east-1
            CkXml xml;
            if (!sbBucketRegion.ContentsEqual("us-east-1", true)) {
                xml.put_Tag("CreateBucketConfiguration");
                xml.AddAttribute("xmlns", "http://s3.amazonaws.com/doc/2006-03-01/");
                xml.UpdateChildContent("LocationConstraint", _bucketRegion.c_str());
            }
            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + globalEndpoint).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Make the call to create the bucket
            std::string createPath = _bAwsPath ? "/" : ("/" + bucketName);
            const char* responseStr = nullptr;
            if (!sbBucketRegion.ContentsEqual("us-east-1", true)) {
                responseStr = conn->rest.fullRequestString("PUT", createPath.c_str(), xml.getXml());
            }
            else {
                // If the bucket is to be created in the us-east-1 region (the default region)
                // just send a PUT with no body
                responseStr = conn->rest.fullRequestNoBody("PUT", createPath.c_str());
            }

            if (conn->rest.get_LastMethodSuccess() != true) {
                _logger.LogError("ANSAWSS3::CreateBucket - Request failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            int statusCode = conn->rest.get_ResponseStatusCode();

            if (statusCode == 200) {
                _logger.LogDebug("ANSAWSS3::CreateBucket",
                    "Successfully created bucket: " + bucketName + " in region: " + _bucketRegion,
                    __FILE__, __LINE__);
                createSuccess = true;
            }
            else {
                std::string errorMsg = "HTTP " + std::to_string(statusCode);

                if (responseStr != nullptr && responseStr[0] != '\0') {
                    CkXml responseXml;
                    if (responseXml.LoadXml(responseStr)) {
                        const char* errorCode = responseXml.getChildContent("Code");
                        const char* errorMessage = responseXml.getChildContent("Message");

                        if (errorCode != nullptr) {
                            errorMsg += " - " + std::string(errorCode);
                        }
                        if (errorMessage != nullptr) {
                            errorMsg += ": " + std::string(errorMessage);
                        }
                    }
                    else {
                        errorMsg += "\n" + std::string(responseStr);
                    }
                }

                if (statusCode == 409) {
                    _logger.LogError("ANSAWSS3::CreateBucket", errorMsg, __FILE__, __LINE__);
                }
                else {
                    _logger.LogError("ANSAWSS3::CreateBucket", errorMsg, __FILE__, __LINE__);
                }
            }

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::CreateBucket",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
        }

        return createSuccess;
    }
    bool ANSAWSS3::DeleteBucket(const std::string& bucketName) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::DeleteBucket",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty()) {
            _logger.LogError("ANSAWSS3::DeleteBucket",
                "Bucket name cannot be empty",
                __FILE__, __LINE__);
            return false;
        }

        bool deleteSuccess = false;

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("DeleteBucket", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Configure AWS authentication
            conn->rest.ClearAuth();
            conn->authAws.put_AccessKey(_accessKey.c_str());
            conn->authAws.put_SecretKey(_secretKey.c_str());
            conn->authAws.put_ServiceName(_serviceName.c_str());

            bool authSuccess = conn->rest.SetAuthAws(conn->authAws);
            if (!authSuccess) {
                _logger.LogError("ANSAWSS3::DeleteBucket",
                    "Failed to set AWS authentication: " + std::string(conn->rest.lastErrorText()),
                    __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Set bucket-specific endpoint
            std::string globalEndpoint = _serviceName + "." + _baseDomain;
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + globalEndpoint).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            std::string deletePath = _bAwsPath ? "/" : ("/" + bucketName);
            CkStringBuilder sbResponse;
            bool success = conn->rest.FullRequestNoBodySb("DELETE", deletePath.c_str(), sbResponse);

            if (!success) {
                _logger.LogError("ANSAWSS3::DeleteBucket",
                    "Failed to send DELETE request: " + std::string(conn->rest.lastErrorText()),
                    __FILE__, __LINE__);
            }
            else {
                int statusCode = conn->rest.get_ResponseStatusCode();

                // S3 returns 204 (No Content) for successful bucket deletion
                if (statusCode == 204) {
                    _logger.LogDebug("ANSAWSS3::DeleteBucket",
                        "Successfully deleted bucket: " + bucketName,
                        __FILE__, __LINE__);
                    deleteSuccess = true;
                }
                else if (statusCode == 404) {
                    _logger.LogWarn("ANSAWSS3::DeleteBucket",
                        "Bucket not found (already deleted?): " + bucketName,
                        __FILE__, __LINE__);
                }
                else if (statusCode == 409) {
                    // Bucket not empty
                    std::string errorMsg = "HTTP 409 - Bucket is not empty and cannot be deleted";

                    std::string response = sbResponse.getAsString();
                    if (!response.empty()) {
                        CkXml responseXml;
                        if (responseXml.LoadXml(response.c_str())) {
                            const char* errorCode = responseXml.getChildContent("Code");
                            const char* errorMessage = responseXml.getChildContent("Message");

                            if (errorCode != nullptr) {
                                errorMsg += " - " + std::string(errorCode);
                            }
                            if (errorMessage != nullptr) {
                                errorMsg += ": " + std::string(errorMessage);
                            }
                        }
                    }

                    _logger.LogError("ANSAWSS3::DeleteBucket", errorMsg, __FILE__, __LINE__);
                }
                else {
                    std::string errorMsg = "HTTP " + std::to_string(statusCode);
                    std::string response = sbResponse.getAsString();
                    if (!response.empty()) {
                        errorMsg += " - " + response;
                    }
                    _logger.LogError("ANSAWSS3::DeleteBucket", errorMsg, __FILE__, __LINE__);
                }
            }

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::DeleteBucket",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
        }

        return deleteSuccess;
    }
    bool ANSAWSS3::CreateFolder(const std::string& bucketName, const std::string& prefix) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::CreateFolder",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || prefix.empty()) {
            _logger.LogError("ANSAWSS3::CreateFolder",
                "Bucket name or folder path is empty",
                __FILE__, __LINE__);
            return false;
        }

        bool createSuccess = false;

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("CreateFolder", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Ensure folder path ends with "/"
            std::string normalizedPath = prefix;
            if (normalizedPath.back() != '/') {
                normalizedPath += '/';
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Object path is the folder name with trailing slash
            std::string objectPath = _bAwsPath ? ("/" + normalizedPath) : ("/" + bucketName + "/" + normalizedPath);

            // Create a zero-byte object to represent the folder
            // Use PUT with empty body
            const char* responseStr = conn->rest.fullRequestNoBody("PUT", objectPath.c_str());

            if (conn->rest.get_LastMethodSuccess() != true) {
                _logger.LogError("ANSAWSS3::CreateFolder - Request failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            int statusCode = conn->rest.get_ResponseStatusCode();

            if (statusCode == 200) {
                _logger.LogDebug("ANSAWSS3::CreateFolder",
                    "Successfully created folder: " + normalizedPath + " in bucket: " + bucketName,
                    __FILE__, __LINE__);
                createSuccess = true;
            }
            else {
                std::string errorMsg = "HTTP " + std::to_string(statusCode);

                if (responseStr != nullptr && responseStr[0] != '\0') {
                    CkXml responseXml;
                    if (responseXml.LoadXml(responseStr)) {
                        const char* errorCode = responseXml.getChildContent("Code");
                        const char* errorMessage = responseXml.getChildContent("Message");

                        if (errorCode != nullptr) {
                            errorMsg += " - " + std::string(errorCode);
                        }
                        if (errorMessage != nullptr) {
                            errorMsg += ": " + std::string(errorMessage);
                        }
                    }
                    else {
                        errorMsg += " - " + std::string(responseStr);
                    }
                }

                _logger.LogError("ANSAWSS3::CreateFolder", errorMsg, __FILE__, __LINE__);
            }

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::CreateFolder",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
        }

        return createSuccess;
    }
    bool ANSAWSS3::DeleteFolder(const std::string& bucketName, const std::string& prefix) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::DeleteFolder",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || prefix.empty()) {
            _logger.LogError("ANSAWSS3::DeleteFolder",
                "Bucket name or folder path is empty",
                __FILE__, __LINE__);
            return false;
        }

        bool deleteSuccess = false;

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("DeleteFolder", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Ensure folder path ends with "/"
            std::string normalizedPath = prefix;
            if (normalizedPath.back() != '/') {
                normalizedPath += '/';
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            std::string objectPath = _bAwsPath ? ("/" + normalizedPath) : ("/" + bucketName + "/" + normalizedPath);

            CkStringBuilder sbResponse;
            bool success = conn->rest.FullRequestNoBodySb("DELETE", objectPath.c_str(), sbResponse);

            if (!success) {
                _logger.LogError("ANSAWSS3::DeleteFolder",
                    "Failed to send DELETE request: " + std::string(conn->rest.lastErrorText()),
                    __FILE__, __LINE__);
            }
            else {
                int statusCode = conn->rest.get_ResponseStatusCode();

                // S3 returns 204 (No Content) for successful deletion
                if (statusCode == 204 || statusCode == 200) {
                    _logger.LogDebug("ANSAWSS3::DeleteFolder",
                        "Successfully deleted folder marker: " + normalizedPath + " from bucket: " + bucketName,
                        __FILE__, __LINE__);
                    deleteSuccess = true;
                }
                else if (statusCode == 404) {
                    _logger.LogWarn("ANSAWSS3::DeleteFolder",
                        "Folder marker not found (already deleted?): " + normalizedPath,
                        __FILE__, __LINE__);
                }
                else {
                    std::string errorMsg = "HTTP " + std::to_string(statusCode);
                    std::string response = sbResponse.getAsString();
                    if (!response.empty()) {
                        errorMsg += " - " + response;
                    }
                    _logger.LogError("ANSAWSS3::DeleteFolder", errorMsg, __FILE__, __LINE__);
                }
            }

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::DeleteFolder",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
        }

        return deleteSuccess;
    }
    std::string ANSAWSS3::GetBucketRegion(const std::string& bucketName) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::GetBucketRegion",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return "";
        }

        if (bucketName.empty()) {
            _logger.LogError("ANSAWSS3::GetBucketRegion",
                "Bucket name is empty",
                __FILE__, __LINE__);
            return "";
        }

        std::string region = "";

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("GetBucketRegion", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return "";
            }

           // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Send the GET request to query the bucket location
            std::string locationPath = _bAwsPath ? "/?location" : ("/" + bucketName + "?location");
            const char* strResult = conn->rest.fullRequestNoBody("GET", locationPath.c_str());

            if (conn->rest.get_LastMethodSuccess() != true) {
                _logger.LogError("ANSAWSS3::GetBucketRegion - Request failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return "";
            }

            int responseStatusCode = conn->rest.get_ResponseStatusCode();

            if (responseStatusCode != 200) {
                std::string errorMsg = "HTTP " + std::to_string(responseStatusCode);
                if (strResult != nullptr && strResult[0] != '\0') {
                    errorMsg += " - " + std::string(strResult);
                }
                _logger.LogError("ANSAWSS3::GetBucketRegion", errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return "";
            }

            // Parse XML response
            CkXml xml;
            bool success = xml.LoadXml(strResult);
            if (!success) {
                _logger.LogError("ANSAWSS3::GetBucketRegion - Failed to parse XML",
                    xml.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return "";
            }

            // Get the region from XML content
            const char* regionContent = xml.content();

            if (regionContent != nullptr && regionContent[0] != '\0') {
                region = std::string(regionContent);

                // AWS returns empty string for us-east-1 (classic region)
                // Some implementations may return "null" or empty
                if (region.empty() || region == "null") {
                    region = "us-east-1";
                    _logger.LogDebug("ANSAWSS3::GetBucketRegion",
                        "Bucket '" + bucketName + "' is in default region: us-east-1",
                        __FILE__, __LINE__);
                }
                else {
                    _logger.LogDebug("ANSAWSS3::GetBucketRegion",
                        "Bucket '" + bucketName + "' is in region: " + region,
                        __FILE__, __LINE__);
                }
            }
            else {
                // Empty response typically means us-east-1
                region = "us-east-1";
                _logger.LogDebug("ANSAWSS3::GetBucketRegion",
                    "Empty response - assuming default region: us-east-1",
                    __FILE__, __LINE__);
            }

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::GetBucketRegion",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
        }

        return region;
    }

	// Uploads text data from a file to the specified S3 bucket
    bool ANSAWSS3::UploadTextData(const std::string& bucketName, const std::string& textFilePath, std::string& uploadedFilePath) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::UploadTextData",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || textFilePath.empty()) {
            _logger.LogError("ANSAWSS3::UploadTextData",
                "Bucket name or file path is empty",
                __FILE__, __LINE__);
            return false;
        }

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("UploadTextData", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Read text file
            CkFileAccess fac;
            const char* fileContents = fac.readEntireTextFile(textFilePath.c_str(), "utf-8");
            if (!fac.get_LastMethodSuccess()) {
                _logger.LogError("ANSAWSS3::UploadTextData - Failed to read file",
                    fac.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Validate file contents
            if (fileContents == nullptr || fileContents[0] == '\0') {
                _logger.LogError("ANSAWSS3::UploadTextData",
                    "File is empty: " + textFilePath,
                    __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Extract filename
            std::string fileName = ExtractFileName(textFilePath);
            if (fileName.empty()) {
                _logger.LogError("ANSAWSS3::UploadTextData",
                    "Failed to extract filename from path: " + textFilePath,
                    __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Determine content type
            std::string contentType = GetContentType(textFilePath);

            // Set headers
            conn->rest.AddHeader("Content-Type", contentType.c_str());
            conn->rest.AddHeader("Content-Encoding", "gzip");
            conn->rest.AddHeader("Expect", "100-continue");

            // Construct S3 object path
            std::string objectPath = _bAwsPath ? ("/" + fileName) : ("/" + bucketName + "/" + fileName);

            _logger.LogDebug("ANSAWSS3::UploadTextData",
                "Uploading file: " + fileName + " (" + contentType + ")",
                __FILE__, __LINE__);

            // Upload to S3
            const char* responseBodyStr = conn->rest.fullRequestString("PUT", objectPath.c_str(), fileContents);

            if (!conn->rest.get_LastMethodSuccess()) {
                _logger.LogError("ANSAWSS3::UploadTextData - Upload failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Check HTTP status code
            int statusCode = conn->rest.get_ResponseStatusCode();
            if (statusCode != 200) {
                std::string errorMsg = "HTTP " + std::to_string(statusCode);
                if (responseBodyStr != nullptr && responseBodyStr[0] != '\0') {
                    errorMsg += " - " + std::string(responseBodyStr);
                }

                _logger.LogError("ANSAWSS3::UploadTextData", errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            {
                std::string scheme = _bTls ? "https://" : "http://";
                std::string uploadedUrl = scheme + _fullAWSURL + "/" + bucketName + "/" + fileName;
                uploadedFilePath = uploadedUrl;
                _logger.LogDebug("ANSAWSS3::UploadTextData",
                    "Successfully uploaded: " + fileName + " to bucket: " + bucketName + " | URL: " + uploadedUrl,
                    __FILE__, __LINE__);
            }

            ReleaseConnection(std::move(conn));
            return true;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::UploadTextData", e.what(), __FILE__, __LINE__);
            return false;
        }
    }
    bool ANSAWSS3::UploadBinaryData(const std::string& bucketName, const std::string& dataFilePath, std::string& uploadedFilePath) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::UploadBinaryData",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || dataFilePath.empty()) {
            _logger.LogError("ANSAWSS3::UploadBinaryData",
                "Bucket name or file path is empty",
                __FILE__, __LINE__);
            return false;
        }

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("UploadBinaryData", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Load binary file
            CkBinData binData;
            if (!binData.LoadFile(dataFilePath.c_str())) {
                _logger.LogError("ANSAWSS3::UploadBinaryData - Failed to load file",
                    binData.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Extract filename from path
            std::string fileName = ExtractFileName(dataFilePath);
            if (fileName.empty()) {
                _logger.LogError("ANSAWSS3::UploadBinaryData",
                    "Failed to extract filename from path: " + dataFilePath,
                    __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Determine content type from file extension
            std::string contentType = GetContentType(dataFilePath);

            // Set headers
            conn->rest.AddHeader("Content-Type", contentType.c_str());
            conn->rest.AddHeader("Expect", "100-continue");

            // Construct S3 object path
            std::string objectPath = _bAwsPath ? ("/" + fileName) : ("/" + bucketName + "/" + fileName);

            _logger.LogDebug("ANSAWSS3::UploadBinaryData",
                "Uploading file: " + fileName + " (" + contentType + ")",
                __FILE__, __LINE__);

            // Upload to S3
            CkStringBuilder sbResponse;
            if (!conn->rest.FullRequestBd("PUT", objectPath.c_str(), binData, sbResponse)) {
                _logger.LogError("ANSAWSS3::UploadBinaryData - Upload failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Check HTTP status code
            int statusCode = conn->rest.get_ResponseStatusCode();
            if (statusCode != 200) {
                std::string errorMsg = "HTTP " + std::to_string(statusCode);
                std::string response = sbResponse.getAsString();
                if (!response.empty()) {
                    errorMsg += " - " + response;
                }

                _logger.LogError("ANSAWSS3::UploadBinaryData", errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            {
                std::string scheme = _bTls ? "https://" : "http://";
                std::string uploadedUrl = scheme + _fullAWSURL + "/" + bucketName + "/" + fileName;
                uploadedFilePath = uploadedUrl;
                _logger.LogDebug("ANSAWSS3::UploadBinaryData",
                    "Successfully uploaded: " + fileName + " to bucket: " + bucketName + " | URL: " + uploadedUrl,
                    __FILE__, __LINE__);
            }

            ReleaseConnection(std::move(conn));
            return true;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::UploadBinaryData", e.what(), __FILE__, __LINE__);
            return false;
        }
    }
    
    bool ANSAWSS3::UploadPrefixBinaryData(const std::string& bucketName, const std::string& prefix, const std::string& dataFilePath, const std::string& objectName, std::string& uploadedFilePath) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::UploadPrefixBinaryData",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || dataFilePath.empty()) {
            _logger.LogError("ANSAWSS3::UploadPrefixBinaryData",
                "Bucket name or file path is empty",
                __FILE__, __LINE__);
            return false;
        }

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("UploadPrefixBinaryData", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Load binary file
            CkBinData binData;
            if (!binData.LoadFile(dataFilePath.c_str())) {
                _logger.LogError("ANSAWSS3::UploadPrefixBinaryData - Failed to load file",
                    binData.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Extract filename from path
            std::string fileName = objectName;
            if (fileName.empty()) {
                fileName = ExtractFileName(dataFilePath);
                if (fileName.empty()) {
                    _logger.LogError("ANSAWSS3::UploadPrefixBinaryData",
                        "Failed to extract filename from path: " + dataFilePath,
                        __FILE__, __LINE__);
                    ReleaseConnection(std::move(conn));
                    return false;
                }
            }

            // Construct object path with optional prefix
            std::string objectPath;
            if (!prefix.empty()) {
                // Normalize prefix: ensure it doesn't start with / but ends with /
                std::string normalizedPrefix = prefix;

                // Remove leading slash if present
                if (normalizedPrefix[0] == '/') {
                    normalizedPrefix = normalizedPrefix.substr(1);
                }

                // Add trailing slash if not present
                if (!normalizedPrefix.empty() && normalizedPrefix.back() != '/') {
                    normalizedPrefix += '/';
                }

                objectPath = _bAwsPath ? ("/" + normalizedPrefix + fileName) : ("/" + bucketName + "/" + normalizedPrefix + fileName);
            }
            else {
                objectPath = _bAwsPath ? ("/" + fileName) : ("/" + bucketName + "/" + fileName);
            }

            // Determine content type from file extension
            std::string contentType = GetContentType(dataFilePath);

            // Set headers
            conn->rest.AddHeader("Content-Type", contentType.c_str());
            conn->rest.AddHeader("Expect", "100-continue");

            _logger.LogDebug("ANSAWSS3::UploadPrefixBinaryData",
                "Uploading file: " + fileName + " (" + contentType + ") to: " + objectPath,
                __FILE__, __LINE__);

            // Upload to S3
            CkStringBuilder sbResponse;
            if (!conn->rest.FullRequestBd("PUT", objectPath.c_str(), binData, sbResponse)) {
                _logger.LogError("ANSAWSS3::UploadPrefixBinaryData - Upload failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Check HTTP status code
            int statusCode = conn->rest.get_ResponseStatusCode();
            if (statusCode != 200) {
                std::string errorMsg = "HTTP " + std::to_string(statusCode);
                std::string response = sbResponse.getAsString();
                if (!response.empty()) {
                    errorMsg += " - " + response;
                }

                _logger.LogError("ANSAWSS3::UploadPrefixBinaryData", errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            {
                std::string scheme = _bTls ? "https://" : "http://";
                std::string uploadedUrl = scheme + _fullAWSURL + "/" + bucketName + objectPath;
                uploadedFilePath = uploadedUrl;
                _logger.LogDebug("ANSAWSS3::UploadPrefixBinaryData",
                    "Successfully uploaded to: " + objectPath + " in bucket: " + bucketName + " | URL: " + uploadedUrl,
                    __FILE__, __LINE__);
            }

            ReleaseConnection(std::move(conn));
            return true;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::UploadPrefixBinaryData", e.what(), __FILE__, __LINE__);
            return false;
        }
    }

    bool ANSAWSS3::UploadFileStream(const std::string& bucketName, const std::string& dataFilePath, std::string& uploadedFilePath) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::UploadFileStream",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || dataFilePath.empty()) {
            _logger.LogError("ANSAWSS3::UploadFileStream",
                "Bucket name or file path is empty",
                __FILE__, __LINE__);
            return false;
        }

        bool uploadSuccess = false;

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("UploadFileStream", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Set up file stream
            CkStream fileStream;
            fileStream.put_SourceFile(dataFilePath.c_str());

            // Extract filename for S3 object key
            std::string fileName = ExtractFileName(dataFilePath);
            std::string objectPath = _bAwsPath ? ("/" + fileName) : ("/" + bucketName + "/" + fileName);

            // Upload to S3
            // If the application provided the SHA-256 hash of the file contents (as shown above)
            // then file is streamed and never has to completely reside in memory.
            const char* responseStr = conn->rest.fullRequestStream("PUT", objectPath.c_str(), fileStream);

            if (conn->rest.get_LastMethodSuccess() != true) {
                _logger.LogError("ANSAWSS3::UploadFileStream - Upload failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
            }
            else if (conn->rest.get_ResponseStatusCode() != 200) {
                // Examine the request/response to see what happened.
                std::string errorMsg = "HTTP " + std::to_string(conn->rest.get_ResponseStatusCode());
                if (responseStr != nullptr && responseStr[0] != '\0') {
                    errorMsg += " - " + std::string(responseStr);
                }
                _logger.LogError("ANSAWSS3::UploadFileStream", errorMsg, __FILE__, __LINE__);
            }
            else {
                // Success
                {
                    std::string scheme = _bTls ? "https://" : "http://";
                    std::string uploadedUrl = scheme + _fullAWSURL + "/" + bucketName + "/" + fileName;
                    uploadedFilePath = uploadedUrl;
                    _logger.LogDebug("ANSAWSS3::UploadFileStream",
                        "Successfully uploaded file: " + fileName + " to bucket: " + bucketName + " | URL: " + uploadedUrl,
                        __FILE__, __LINE__);
                }
                uploadSuccess = true;
            }

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::UploadFileStream",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
        }

        return uploadSuccess;
    }
    bool ANSAWSS3::UploadMultipartData(const std::string& bucketName,const std::string& dataFilePath, std::string& uploadedFilePath, int partSize) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::UploadMultipartData",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || dataFilePath.empty()) {
            _logger.LogError("ANSAWSS3::UploadMultipartData",
                "Bucket name or file path is empty",
                __FILE__, __LINE__);
            return false;
        }

        // Validate part size (minimum 5MB enforced by AWS)
        if (partSize < 5242880) {
            _logger.LogError("ANSAWSS3::UploadMultipartData",
                "Part size must be at least 5MB (5242880 bytes)",
                __FILE__, __LINE__);
            return false;
        }

        try {
            // Check if file exists
            CkFileAccess fac;
            if (!fac.FileExists(dataFilePath.c_str())) {
                _logger.LogError("ANSAWSS3::UploadMultipartData",
                    "File not found: " + dataFilePath,
                    __FILE__, __LINE__);
                return false;
            }

            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("UploadMultipartData", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Extract filename and construct object path
            std::string fileName = ExtractFileName(dataFilePath);
            if (fileName.empty()) {
                _logger.LogError("ANSAWSS3::UploadMultipartData",
                    "Failed to extract filename from path: " + dataFilePath,
                    __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            std::string objectPath = _bAwsPath ? ("/" + fileName) : ("/" + bucketName + "/" + fileName);

            // ====================================================================
            // STEP 1: INITIATE MULTIPART UPLOAD
            // ====================================================================
            _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                "Step 1: Initiating multipart upload for: " + fileName,
                __FILE__, __LINE__);

            conn->rest.ClearAllQueryParams();
            conn->rest.AddQueryParam("uploads", "");

            const char* responseXml = conn->rest.fullRequestNoBody("POST", objectPath.c_str());

            if (!conn->rest.get_LastMethodSuccess()) {
                _logger.LogError("ANSAWSS3::UploadMultipartData - Initiation failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            if (conn->rest.get_ResponseStatusCode() != 200) {
                std::string errorMsg = "HTTP " + std::to_string(conn->rest.get_ResponseStatusCode());
                if (responseXml != nullptr && responseXml[0] != '\0') {
                    errorMsg += " - " + std::string(responseXml);
                }
                _logger.LogError("ANSAWSS3::UploadMultipartData - Initiation failed",
                    errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Parse response to get UploadId
            CkXml xmlInit;
            if (!xmlInit.LoadXml(responseXml)) {
                _logger.LogError("ANSAWSS3::UploadMultipartData - XML parse error",
                    xmlInit.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            const char* uploadId = xmlInit.getChildContent("UploadId");
            if (uploadId == nullptr || uploadId[0] == '\0') {
                _logger.LogError("ANSAWSS3::UploadMultipartData",
                    "UploadId not found in response",
                    __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                "Multipart upload initiated. UploadId: " + std::string(uploadId),
                __FILE__, __LINE__);

            // ====================================================================
            // STEP 2: UPLOAD PARTS
            // ====================================================================
            _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                "Step 2: Uploading parts",
                __FILE__, __LINE__);

            // Calculate number of parts
            fac.OpenForRead(dataFilePath.c_str());
            int numParts = fac.GetNumBlocks(partSize);
            fac.FileClose();

            _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                "File will be uploaded in " + std::to_string(numParts) + " parts",
                __FILE__, __LINE__);

            // Setup parts list XML file path
            std::string fileFolderPath = dataFilePath.substr(0, dataFilePath.find_last_of("/\\"));
            std::string partsListFilePath = fileFolderPath + "/partsList_" + fileName + ".xml";

            // Load or create parts list XML
            CkXml partsListXml;
            if (fac.FileExists(partsListFilePath.c_str())) {
                if (!partsListXml.LoadXmlFile(partsListFilePath.c_str())) {
                    _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                        "Failed to load existing parts list, creating new one",
                        __FILE__, __LINE__);
                }
            }

            partsListXml.put_Tag("CompleteMultipartUpload");

            // Upload each part
            CkStringBuilder sbPartNumber;
            int successfulParts = 0;

            for (int partNumber = 1; partNumber <= numParts; ++partNumber) {
                _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                    "Processing part " + std::to_string(partNumber) + " of " +
                    std::to_string(numParts),
                    __FILE__, __LINE__);

                // Convert part number to string
                sbPartNumber.Clear();
                sbPartNumber.AppendInt(partNumber);

                // Check if this part was already uploaded
                bool partAlreadyUploaded = false;
                int numUploadedParts = partsListXml.get_NumChildren();

                if (numUploadedParts > 0) {
                    CkXml* xRec0 = partsListXml.GetChild(0);
                    CkXml* foundRec = xRec0->FindNextRecord("PartNumber", sbPartNumber.getAsString());

                    if (xRec0->get_LastMethodSuccess()) {
                        partAlreadyUploaded = true;
                        _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                            "Part " + std::to_string(partNumber) + " already uploaded, skipping",
                            __FILE__, __LINE__);
                        successfulParts++;
                        delete foundRec;
                    }
                    delete xRec0;
                }

                if (!partAlreadyUploaded) {
                    // Setup stream for this part
                    CkStream fileStream;
                    fileStream.put_SourceFile(dataFilePath.c_str());
                    fileStream.put_SourceFilePartSize(partSize);
                    fileStream.put_SourceFilePart(partNumber - 1); // 0-based index

                    // Set query parameters for this part
                    conn->rest.ClearAllQueryParams();
                    conn->rest.AddQueryParam("partNumber", sbPartNumber.getAsString());
                    conn->rest.AddQueryParam("uploadId", uploadId);

                    // Upload the part - CRITICAL FIX: Use objectPath instead of hardcoded name
                    const char* responseStr = conn->rest.fullRequestStream("PUT", objectPath.c_str(), fileStream);

                    if (!conn->rest.get_LastMethodSuccess()) {
                        _logger.LogError("ANSAWSS3::UploadMultipartData",
                            "Failed to upload part " + std::to_string(partNumber) + ": " +
                            conn->rest.lastErrorText(),
                            __FILE__, __LINE__);
                        ReleaseConnection(std::move(conn));
                        return false;
                    }

                    if (conn->rest.get_ResponseStatusCode() != 200) {
                        std::string errorMsg = "Part " + std::to_string(partNumber) +
                            " - HTTP " + std::to_string(conn->rest.get_ResponseStatusCode());
                        if (responseStr != nullptr && responseStr[0] != '\0') {
                            errorMsg += " - " + std::string(responseStr);
                        }

                        _logger.LogError("ANSAWSS3::UploadMultipartData - Upload failed",
                            errorMsg, __FILE__, __LINE__);
                        ReleaseConnection(std::move(conn));
                        return false;
                    }

                    // Get ETag from response header
                    const char* etag = conn->rest.responseHdrByName("ETag");
                    if (!conn->rest.get_LastMethodSuccess() || etag == nullptr || etag[0] == '\0') {
                        _logger.LogError("ANSAWSS3::UploadMultipartData",
                            "ETag not found in response for part " + std::to_string(partNumber),
                            __FILE__, __LINE__);
                        ReleaseConnection(std::move(conn));
                        return false;
                    }

                    // Add part to XML list
                    CkXml* xPart = partsListXml.NewChild("Part", "");
                    xPart->NewChildInt2("PartNumber", partNumber);
                    xPart->NewChild2("ETag", etag);
                    delete xPart;

                    // Save parts list after each successful upload
                    if (!partsListXml.SaveXml(partsListFilePath.c_str())) {
                        _logger.LogError("ANSAWSS3::UploadMultipartData",
                            "Failed to save parts list: " + std::string(partsListXml.lastErrorText()),
                            __FILE__, __LINE__);
                    }

                    successfulParts++;
                    _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                        "Part " + std::to_string(partNumber) + " uploaded successfully",
                        __FILE__, __LINE__);
                }
            }

            _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                "All parts uploaded (" + std::to_string(successfulParts) + "/" +
                std::to_string(numParts) + ")",
                __FILE__, __LINE__);

            // ====================================================================
            // STEP 3: COMPLETE MULTIPART UPLOAD
            // ====================================================================
            _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                "Step 3: Completing multipart upload",
                __FILE__, __LINE__);

            conn->rest.ClearAllQueryParams();
            conn->rest.AddQueryParam("uploadId", uploadId);

            responseXml = conn->rest.fullRequestString("POST", objectPath.c_str(), partsListXml.getXml());

            if (!conn->rest.get_LastMethodSuccess()) {
                _logger.LogError("ANSAWSS3::UploadMultipartData - Completion failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            if (conn->rest.get_ResponseStatusCode() != 200) {
                std::string errorMsg = "HTTP " + std::to_string(conn->rest.get_ResponseStatusCode());
                if (responseXml != nullptr && responseXml[0] != '\0') {
                    errorMsg += " - " + std::string(responseXml);
                }

                _logger.LogError("ANSAWSS3::UploadMultipartData - Completion failed",
                    errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Parse completion response
            CkXml xmlComplete;
            if (xmlComplete.LoadXml(responseXml)) {
                const char* location = xmlComplete.getChildContent("Location");
                const char* eTag = xmlComplete.getChildContent("ETag");

                if (location != nullptr) {
                    _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                        "Upload completed. Location: " + std::string(location),
                        __FILE__, __LINE__);
                }
            }

            // Clean up parts list file on success
            if (fac.FileExists(partsListFilePath.c_str())) {
                fac.FileDelete(partsListFilePath.c_str());
            }

            std::string scheme = _bTls ? "https://" : "http://";
            uploadedFilePath = scheme + _fullAWSURL + "/" + bucketName + "/" + fileName;
            _logger.LogDebug("ANSAWSS3::UploadMultipartData",
                "Multipart upload completed successfully for: " + fileName,
                __FILE__, __LINE__);

            ReleaseConnection(std::move(conn));
            return true;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::UploadMultipartData", e.what(), __FILE__, __LINE__);
            return false;
        }
    }
    bool ANSAWSS3::UploadPrefixMultipartData(const std::string& bucketName, const std::string& prefix,const std::string& dataFilePath, const std::string& objectName, std::string& uploadedFilePath, int partSize) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::UploadPrefixMultipartData",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || dataFilePath.empty()) {
            _logger.LogError("ANSAWSS3::UploadPrefixMultipartData",
                "Bucket name or file path is empty",
                __FILE__, __LINE__);
            return false;
        }

        // Validate part size (minimum 5MB enforced by AWS)
        if (partSize < 5242880) {
            _logger.LogError("ANSAWSS3::UploadPrefixMultipartData",
                "Part size must be at least 5MB (5242880 bytes)",
                __FILE__, __LINE__);
            return false;
        }

        try {
            // Check if file exists
            CkFileAccess fac;
            if (!fac.FileExists(dataFilePath.c_str())) {
                _logger.LogError("ANSAWSS3::UploadPrefixMultipartData",
                    "File not found: " + dataFilePath,
                    __FILE__, __LINE__);
                return false;
            }

            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("UploadPrefixMultipartData", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Extract filename and construct object path with optional prefix
            std::string fileName = objectName;

            if (fileName.empty()) {
                fileName=ExtractFileName(dataFilePath);
                if (fileName.empty()) {
                    _logger.LogError("ANSAWSS3::UploadPrefixMultipartData",
                        "Failed to extract filename from path: " + dataFilePath,
                        __FILE__, __LINE__);
                    ReleaseConnection(std::move(conn));
                    return false;
                }
            }

            // Construct object path with prefix support
            std::string objectPath;
            if (!prefix.empty()) {
                // Normalize prefix: ensure it doesn't start with / but ends with /
                std::string normalizedPrefix = prefix;

                // Remove leading slash if present
                if (normalizedPrefix[0] == '/') {
                    normalizedPrefix = normalizedPrefix.substr(1);
                }

                // Add trailing slash if not present
                if (!normalizedPrefix.empty() && normalizedPrefix.back() != '/') {
                    normalizedPrefix += '/';
                }

                objectPath = _bAwsPath ? ("/" + normalizedPrefix + fileName) : ("/" + bucketName + "/" + normalizedPrefix + fileName);
            }
            else {
                objectPath = _bAwsPath ? ("/" + fileName) : ("/" + bucketName + "/" + fileName);
            }

            _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                "Object path: " + objectPath,
                __FILE__, __LINE__);

            // ====================================================================
            // STEP 1: INITIATE MULTIPART UPLOAD
            // ====================================================================
            _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                "Step 1: Initiating multipart upload for: " + fileName,
                __FILE__, __LINE__);

            conn->rest.ClearAllQueryParams();
            conn->rest.AddQueryParam("uploads", "");

            const char* responseXml = conn->rest.fullRequestNoBody("POST", objectPath.c_str());

            if (!conn->rest.get_LastMethodSuccess()) {
                _logger.LogError("ANSAWSS3::UploadPrefixMultipartData - Initiation failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            if (conn->rest.get_ResponseStatusCode() != 200) {
                std::string errorMsg = "HTTP " + std::to_string(conn->rest.get_ResponseStatusCode());
                if (responseXml != nullptr && responseXml[0] != '\0') {
                    errorMsg += " - " + std::string(responseXml);
                }
                _logger.LogError("ANSAWSS3::UploadPrefixMultipartData - Initiation failed",
                    errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Parse response to get UploadId
            CkXml xmlInit;
            if (!xmlInit.LoadXml(responseXml)) {
                _logger.LogError("ANSAWSS3::UploadPrefixMultipartData - XML parse error",
                    xmlInit.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            const char* uploadId = xmlInit.getChildContent("UploadId");
            if (uploadId == nullptr || uploadId[0] == '\0') {
                _logger.LogError("ANSAWSS3::UploadPrefixMultipartData",
                    "UploadId not found in response",
                    __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                "Multipart upload initiated. UploadId: " + std::string(uploadId),
                __FILE__, __LINE__);

            // ====================================================================
            // STEP 2: UPLOAD PARTS
            // ====================================================================
            _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                "Step 2: Uploading parts",
                __FILE__, __LINE__);

            // Calculate number of parts
            fac.OpenForRead(dataFilePath.c_str());
            int numParts = fac.GetNumBlocks(partSize);
            fac.FileClose();

            _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                "File will be uploaded in " + std::to_string(numParts) + " parts",
                __FILE__, __LINE__);

            // Setup parts list XML file path (use sanitized filename for local storage)
            std::string fileFolderPath = dataFilePath.substr(0, dataFilePath.find_last_of("/\\"));

            // Create a safe filename for the parts list (replace path separators)
            std::string safeFileName = fileName;
            std::replace(safeFileName.begin(), safeFileName.end(), '/', '_');
            std::replace(safeFileName.begin(), safeFileName.end(), '\\', '_');

            std::string partsListFilePath = fileFolderPath + "/partsList_" + safeFileName + ".xml";

            // Load or create parts list XML
            CkXml partsListXml;
            if (fac.FileExists(partsListFilePath.c_str())) {
                if (!partsListXml.LoadXmlFile(partsListFilePath.c_str())) {
                    _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                        "Failed to load existing parts list, creating new one",
                        __FILE__, __LINE__);
                }
            }

            partsListXml.put_Tag("CompleteMultipartUpload");

            // Upload each part
            CkStringBuilder sbPartNumber;
            int successfulParts = 0;

            for (int partNumber = 1; partNumber <= numParts; ++partNumber) {
                _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                    "Processing part " + std::to_string(partNumber) + " of " +
                    std::to_string(numParts),
                    __FILE__, __LINE__);

                // Convert part number to string
                sbPartNumber.Clear();
                sbPartNumber.AppendInt(partNumber);

                // Check if this part was already uploaded
                bool partAlreadyUploaded = false;
                int numUploadedParts = partsListXml.get_NumChildren();

                if (numUploadedParts > 0) {
                    CkXml* xRec0 = partsListXml.GetChild(0);
                    CkXml* foundRec = xRec0->FindNextRecord("PartNumber", sbPartNumber.getAsString());

                    if (xRec0->get_LastMethodSuccess()) {
                        partAlreadyUploaded = true;
                        _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                            "Part " + std::to_string(partNumber) + " already uploaded, skipping",
                            __FILE__, __LINE__);
                        successfulParts++;
                        delete foundRec;
                    }
                    delete xRec0;
                }

                if (!partAlreadyUploaded) {
                    // Setup stream for this part
                    CkStream fileStream;
                    fileStream.put_SourceFile(dataFilePath.c_str());
                    fileStream.put_SourceFilePartSize(partSize);
                    fileStream.put_SourceFilePart(partNumber - 1); // 0-based index

                    // Set query parameters for this part
                    conn->rest.ClearAllQueryParams();
                    conn->rest.AddQueryParam("partNumber", sbPartNumber.getAsString());
                    conn->rest.AddQueryParam("uploadId", uploadId);

                    // Upload the part using the full object path (with prefix)
                    const char* responseStr = conn->rest.fullRequestStream("PUT", objectPath.c_str(), fileStream);

                    if (!conn->rest.get_LastMethodSuccess()) {
                        _logger.LogError("ANSAWSS3::UploadPrefixMultipartData",
                            "Failed to upload part " + std::to_string(partNumber) + ": " +
                            conn->rest.lastErrorText(),
                            __FILE__, __LINE__);
                        ReleaseConnection(std::move(conn));
                        return false;
                    }

                    if (conn->rest.get_ResponseStatusCode() != 200) {
                        std::string errorMsg = "Part " + std::to_string(partNumber) +
                            " - HTTP " + std::to_string(conn->rest.get_ResponseStatusCode());
                        if (responseStr != nullptr && responseStr[0] != '\0') {
                            errorMsg += " - " + std::string(responseStr);
                        }

                        _logger.LogError("ANSAWSS3::UploadPrefixMultipartData - Upload failed",
                            errorMsg, __FILE__, __LINE__);
                        ReleaseConnection(std::move(conn));
                        return false;
                    }

                    // Get ETag from response header
                    const char* etag = conn->rest.responseHdrByName("ETag");
                    if (!conn->rest.get_LastMethodSuccess() || etag == nullptr || etag[0] == '\0') {
                        _logger.LogError("ANSAWSS3::UploadPrefixMultipartData",
                            "ETag not found in response for part " + std::to_string(partNumber),
                            __FILE__, __LINE__);
                        ReleaseConnection(std::move(conn));
                        return false;
                    }

                    // Add part to XML list
                    CkXml* xPart = partsListXml.NewChild("Part", "");
                    xPart->NewChildInt2("PartNumber", partNumber);
                    xPart->NewChild2("ETag", etag);
                    delete xPart;

                    // Save parts list after each successful upload
                    if (!partsListXml.SaveXml(partsListFilePath.c_str())) {
                        _logger.LogError("ANSAWSS3::UploadPrefixMultipartData",
                            "Failed to save parts list: " + std::string(partsListXml.lastErrorText()),
                            __FILE__, __LINE__);
                    }

                    successfulParts++;
                    _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                        "Part " + std::to_string(partNumber) + " uploaded successfully",
                        __FILE__, __LINE__);
                }
            }

            _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                "All parts uploaded (" + std::to_string(successfulParts) + "/" +
                std::to_string(numParts) + ")",
                __FILE__, __LINE__);

            // ====================================================================
            // STEP 3: COMPLETE MULTIPART UPLOAD
            // ====================================================================
            _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                "Step 3: Completing multipart upload",
                __FILE__, __LINE__);

            conn->rest.ClearAllQueryParams();
            conn->rest.AddQueryParam("uploadId", uploadId);

            responseXml = conn->rest.fullRequestString("POST", objectPath.c_str(), partsListXml.getXml());

            if (!conn->rest.get_LastMethodSuccess()) {
                _logger.LogError("ANSAWSS3::UploadPrefixMultipartData - Completion failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            if (conn->rest.get_ResponseStatusCode() != 200) {
                std::string errorMsg = "HTTP " + std::to_string(conn->rest.get_ResponseStatusCode());
                if (responseXml != nullptr && responseXml[0] != '\0') {
                    errorMsg += " - " + std::string(responseXml);
                }

                _logger.LogError("ANSAWSS3::UploadPrefixMultipartData - Completion failed",
                    errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Parse completion response
            CkXml xmlComplete;
            if (xmlComplete.LoadXml(responseXml)) {
                const char* location = xmlComplete.getChildContent("Location");
                const char* eTag = xmlComplete.getChildContent("ETag");

                if (location != nullptr) {
                    _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                        "Upload completed. Location: " + std::string(location),
                        __FILE__, __LINE__);
                }
            }

            // Clean up parts list file on success
            if (fac.FileExists(partsListFilePath.c_str())) {
                fac.FileDelete(partsListFilePath.c_str());
            }

            std::string scheme = _bTls ? "https://" : "http://";
            uploadedFilePath = scheme + _fullAWSURL + "/" + bucketName + objectPath;
            _logger.LogDebug("ANSAWSS3::UploadPrefixMultipartData",
                "Multipart upload completed successfully. S3 path: " + objectPath,
                __FILE__, __LINE__);

            ReleaseConnection(std::move(conn));
            return true;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::UploadPrefixMultipartData", e.what(), __FILE__, __LINE__);
            return false;
        }
    }
    // Upload jpeg data
    bool ANSAWSS3::UploadJpegImage(const std::string& bucketName, unsigned char* jpeg_string, int32 bufferLength, const std::string& fileName, std::string& uploadedFilePath) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::UploadJpegImage",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || bufferLength <= 0) {
            _logger.LogError("ANSAWSS3::UploadJpegImage",
                "Bucket name or buffer length is invalid",
                __FILE__, __LINE__);
            return false;
        }

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("UploadJpegImage", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Load binary file
            CkBinData binData;
            CkByteData jpegBytes;
            jpegBytes.append2(jpeg_string, static_cast<unsigned long>(bufferLength));
            binData.AppendBinary(jpegBytes);

            // Determine content type from file extension
            std::string contentType  = "image/jpeg";

            // Set headers
            conn->rest.AddHeader("Content-Type", contentType.c_str());
            conn->rest.AddHeader("Expect", "100-continue");

            // Construct S3 object path
            std::string objectPath = _bAwsPath ? ("/" + fileName) : ("/" + bucketName + "/" + fileName);

            // Upload to S3
            CkStringBuilder sbResponse;
            if (!conn->rest.FullRequestBd("PUT", objectPath.c_str(), binData, sbResponse)) {
                _logger.LogError("ANSAWSS3::UploadJpegImage - Upload failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Check HTTP status code
            int statusCode = conn->rest.get_ResponseStatusCode();
            if (statusCode != 200) {
                std::string errorMsg = "HTTP " + std::to_string(statusCode);
                std::string response = sbResponse.getAsString();
                if (!response.empty()) {
                    errorMsg += " - " + response;
                }

                _logger.LogError("ANSAWSS3::UploadJpegImage", errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            {
                std::string scheme = _bTls ? "https://" : "http://";
                std::string uploadedUrl = scheme + _fullAWSURL + "/" + bucketName + "/" + fileName;
                uploadedFilePath = uploadedUrl;
                _logger.LogDebug("ANSAWSS3::UploadJpegImage",
                    "Successfully uploaded: " + fileName + " to bucket: " + bucketName + " | URL: " + uploadedUrl,
                    __FILE__, __LINE__);
            }

            ReleaseConnection(std::move(conn));
            return true;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::UploadJpegImage", e.what(), __FILE__, __LINE__);
            return false;
        }
    }
    bool ANSAWSS3::UploadPrefixJpegImage(const std::string& bucketName, const std::string& prefix,unsigned char* jpeg_string,int32 bufferLength,const std::string& fileName, std::string& uploadedFilePath) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::UploadJpegImage",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || bufferLength <= 0 || fileName.empty()) {
            _logger.LogError("ANSAWSS3::UploadJpegImage",
                "Bucket name, buffer length, or filename is invalid",
                __FILE__, __LINE__);
            return false;
        }

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("UploadPrefixJpegImage", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Load binary file
            CkBinData binData;
            CkByteData jpegBytes;
            jpegBytes.append2(jpeg_string, static_cast<unsigned long>(bufferLength));
            binData.AppendBinary(jpegBytes);

            // Set headers
            conn->rest.AddHeader("Content-Type", "image/jpeg");
            conn->rest.AddHeader("Expect", "100-continue");

            // Construct S3 object path with prefix
            std::string objectPath = _bAwsPath ? "/" : ("/" + bucketName + "/");
            if (!prefix.empty()) {
                // Ensure prefix ends with "/" if it doesn't already
                std::string normalizedPrefix = prefix;
                if (normalizedPrefix.back() != '/') {
                    normalizedPrefix += '/';
                }
                objectPath += normalizedPrefix;
            }
            objectPath += fileName;

            _logger.LogDebug("ANSAWSS3::UploadJpegImage",
                "Uploading to: " + objectPath,
                __FILE__, __LINE__);

            // Upload to S3
            CkStringBuilder sbResponse;
            if (!conn->rest.FullRequestBd("PUT", objectPath.c_str(), binData, sbResponse)) {
                _logger.LogError("ANSAWSS3::UploadJpegImage - Upload failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Check HTTP status code
            int statusCode = conn->rest.get_ResponseStatusCode();
            if (statusCode != 200) {
                std::string errorMsg = "HTTP " + std::to_string(statusCode);
                std::string response = sbResponse.getAsString();
                if (!response.empty()) {
                    errorMsg += " - " + response;
                }
                _logger.LogError("ANSAWSS3::UploadJpegImage", errorMsg, __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            {
                std::string scheme = _bTls ? "https://" : "http://";
                std::string uploadedUrl = scheme + _fullAWSURL + "/" + bucketName + objectPath;
                uploadedFilePath = uploadedUrl;
                _logger.LogDebug("ANSAWSS3::UploadPrefixJpegImage",
                    "Successfully uploaded: " + objectPath + " (" + std::to_string(bufferLength) + " bytes) to bucket: " + bucketName + " | URL: " + uploadedUrl,
                    __FILE__, __LINE__);
            }

            ReleaseConnection(std::move(conn));
            return true;
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::UploadJpegImage",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
            return false;
        }
    }
    // Downloads
    bool ANSAWSS3::DownloadFile(const std::string& bucketName,
        const std::string& objectName,
        const std::string& saveFilePath) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::DownloadFile",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || objectName.empty() || saveFilePath.empty()) {
            _logger.LogError("ANSAWSS3::DownloadFile",
                "Bucket name, object name, or save path is empty",
                __FILE__, __LINE__);
            return false;
        }

        bool downloadSuccess = false;

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("DownloadFile", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            // Normalize object name (remove leading slash if present)
            std::string normalizedObjectName = objectName;
            if (!normalizedObjectName.empty() && normalizedObjectName[0] == '/') {
                normalizedObjectName = normalizedObjectName.substr(1);
            }

            std::string objectPath = _bAwsPath ? ("/" + normalizedObjectName) : ("/" + bucketName + "/" + normalizedObjectName);

            _logger.LogDebug("ANSAWSS3::DownloadFile",
                "Downloading: " + normalizedObjectName + " from bucket: " + bucketName,
                __FILE__, __LINE__);

            // Send GET request
            if (!conn->rest.SendReqNoBody("GET", objectPath.c_str())) {
                _logger.LogError("ANSAWSS3::DownloadFile - Request failed",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // Read the response header
            int responseStatusCode = conn->rest.ReadResponseHeader();
            if (responseStatusCode < 0) {
                _logger.LogError("ANSAWSS3::DownloadFile - Failed to read response header",
                    conn->rest.lastErrorText(), __FILE__, __LINE__);
                ReleaseConnection(std::move(conn));
                return false;
            }

            // We expect a 200 response status if the data is coming
            if (responseStatusCode == 200) {
                // Determine the final file path
                std::string finalFilePath;

                // Check if saveFilePath is a directory or a file
                CkFileAccess fac;
                bool isDirectory = false;

                // If path exists and is a directory, or ends with path separator
                if (fac.DirExists(saveFilePath.c_str())) {
                    isDirectory = true;
                }
                else if (!saveFilePath.empty() &&
                    (saveFilePath.back() == '\\' || saveFilePath.back() == '/')) {
                    isDirectory = true;
                }

                if (isDirectory) {
                    // Save path is a directory - append object name
                    finalFilePath = saveFilePath;

                    // Ensure path ends with separator
                    if (!finalFilePath.empty() &&
                        finalFilePath.back() != '\\' &&
                        finalFilePath.back() != '/') {
                        finalFilePath += "\\";
                    }

                    // Extract just the filename from object name (in case it has path separators)
                    std::string filename = normalizedObjectName;
                    size_t lastSlash = filename.find_last_of("/\\");
                    if (lastSlash != std::string::npos) {
                        filename = filename.substr(lastSlash + 1);
                    }

                    finalFilePath += filename;
                }
                else {
                    // Save path is the complete file path
                    finalFilePath = saveFilePath;
                }

                // Ensure the directory exists
                size_t lastSeparator = finalFilePath.find_last_of("/\\");
                if (lastSeparator != std::string::npos) {
                    std::string directory = finalFilePath.substr(0, lastSeparator);

                    // Create directory if it doesn't exist
                    if (!fac.DirExists(directory.c_str())) {
                        if (!fac.DirCreate(directory.c_str())) {
                            _logger.LogError("ANSAWSS3::DownloadFile - Failed to create directory",
                                "Directory: " + directory + " - " + fac.lastErrorText(),
                                __FILE__, __LINE__);
                            ReleaseConnection(std::move(conn));
                            return false;
                        }
                        _logger.LogDebug("ANSAWSS3::DownloadFile",
                            "Created directory: " + directory,
                            __FILE__, __LINE__);
                    }
                }

                // Setup stream to write to file
                CkStream bodyStream;
                bodyStream.put_SinkFile(finalFilePath.c_str());

                // Read the response body to the stream
                if (!conn->rest.ReadRespBodyStream(bodyStream, true)) {
                    _logger.LogError("ANSAWSS3::DownloadFile - Failed to read response body",
                        conn->rest.lastErrorText(), __FILE__, __LINE__);
                }
                else {
                    _logger.LogDebug("ANSAWSS3::DownloadFile",
                        "Successfully downloaded: " + normalizedObjectName + " to: " + finalFilePath,
                        __FILE__, __LINE__);
                    downloadSuccess = true;
                }
            }
            else {
                // Handle non-200 response
                const char* errResponse = conn->rest.readRespBodyString();
                std::string errorMsg = "HTTP " + std::to_string(responseStatusCode);

                if (!conn->rest.get_LastMethodSuccess()) {
                    errorMsg += " - Failed to read error response: " + std::string(conn->rest.lastErrorText());
                }
                else {
                    if (errResponse != nullptr && errResponse[0] != '\0') {
                        errorMsg += " - " + std::string(errResponse);
                    }
                }

                _logger.LogError("ANSAWSS3::DownloadFile", errorMsg, __FILE__, __LINE__);
            }

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::DownloadFile",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
        }

        return downloadSuccess;
    }

    // Delete
    bool ANSAWSS3::DeleteBucketObject(const std::string& bucketName, const std::string& objectName) {
        // Early validation checks
        if (!_isLicenseValid || !_isUnlockCodeValid || !_bConnected) {
            _logger.LogError("ANSAWSS3::DeleteBucketObject",
                !_isLicenseValid ? "Invalid license" : !_isUnlockCodeValid ? "Invalid unlock code" : _retryInProgress.load() ? "Not connected (waiting for internet, retrying in background)" : "Not connected (no internet or connection not established)",
                __FILE__, __LINE__);
            return false;
        }

        if (bucketName.empty() || objectName.empty()) {
            _logger.LogError("ANSAWSS3::DeleteBucketObject",
                "Bucket name or object name is empty",
                __FILE__, __LINE__);
            return false;
        }

        bool deleteSuccess = false;

        try {
            auto conn = AcquireConnection();
            if (!conn) {
                _logger.LogError("DeleteBucketObject", "Failed to acquire S3 connection", __FILE__, __LINE__);
                return false;
            }

            // Set bucket-specific endpoint
            if (_bAwsPath) {
                conn->rest.put_Host((bucketName + "." + _fullAWSURL).c_str());
            } else {
                conn->rest.put_Host(_fullAWSURL.c_str());
            }

            std::string objectPath = _bAwsPath ? ("/" + objectName) : ("/" + bucketName + "/" + objectName);

            CkStringBuilder sbResponse;
            bool success = conn->rest.FullRequestNoBodySb("DELETE", objectPath.c_str(), sbResponse);

            if (!success) {
                _logger.LogError("ANSAWSS3::DeleteBucketObject",
                    "Failed to send DELETE request: " + std::string(conn->rest.lastErrorText()),
                    __FILE__, __LINE__);
            }
            else {
                int statusCode = conn->rest.get_ResponseStatusCode();

                // S3 returns 204 (No Content) for successful deletion
                // Also accept 200 as success
                if (statusCode == 204 || statusCode == 200) {
                    _logger.LogDebug("ANSAWSS3::DeleteBucketObject",
                        "Successfully deleted object: " + objectName + " from bucket: " + bucketName,
                        __FILE__, __LINE__);
                    deleteSuccess = true;
                }
                else if (statusCode == 404) {
                    // Object doesn't exist - you may want to treat this as success or failure
                    // depending on your use case

                    // Uncomment the next line if you want to treat "not found" as success:
                     deleteSuccess = true;
                }
                else {
                    std::string errorMsg = "HTTP " + std::to_string(statusCode);
                    std::string response = sbResponse.getAsString();
                    if (!response.empty()) {
                        errorMsg += " - " + response;
                    }
                    _logger.LogError("ANSAWSS3::DeleteBucketObject", errorMsg, __FILE__, __LINE__);
                }
            }

            ReleaseConnection(std::move(conn));
        }
        catch (const std::exception& e) {
            _logger.LogFatal("ANSAWSS3::DeleteBucketObject",
                std::string("Exception: ") + e.what(),
                __FILE__, __LINE__);
        }
        return deleteSuccess;
    }


}