#include "config_manager.h"
#include "sd_manager.h"
#include "security_manager.h"
#include <cJSON.h>
#include "esp_log.h"
#include "esp_err.h"
#include <string.h>

static const char *TAG = "CONFIG_MANAGER";

// Default configuration with weak passwords that must be changed
static config_t s_default_config = {
    .wifi_ap = {
        .ssid = "P4-Bridge-AP",
        .password = "CHANGE_ME_FIRST_BOOT", // Must be changed on first boot
        .channel = 1,
        .max_connections = 4,
        .ip = "192.168.4.1",
        .gateway = "192.168.4.1",
        .netmask = "255.255.255.0"
    },
    .ethernet = {
        .dhcp_enabled = true,
        .static_ip = "192.168.1.100",
        .gateway = "192.168.1.1",
        .netmask = "255.255.255.0",
        .dns = "8.8.8.8"
    },
    .web_server = {
        .port = 80,
        .auth_enabled = true, // Enable auth by default
        .username = "admin",
        .password = "CHANGE_ME_FIRST_BOOT" // Must be changed on first boot
    },
    .scanner = {
        .arp_timeout_ms = 1000,
        .ping_timeout_ms = 2000,
        .port_scan_timeout_ms = 3000,
        .max_ports_per_scan = 100,
        .scan_interval_ms = 5000
    }
};

static config_t s_current_config;
static bool s_first_boot_detected = false;

// Password strength validation
static bool is_password_strong(const char* password)
{
    if (password == NULL || strlen(password) < 8) {
        return false;
    }
    
    bool has_upper = false, has_lower = false, has_digit = false, has_special = false;
    
    for (int i = 0; password[i] != '\0'; i++) {
        if (password[i] >= 'A' && password[i] <= 'Z') has_upper = true;
        else if (password[i] >= 'a' && password[i] <= 'z') has_lower = true;
        else if (password[i] >= '0' && password[i] <= '9') has_digit = true;
        else has_special = true;
    }
    
    // Require at least 3 of 4 character types
    int types = (has_upper ? 1 : 0) + (has_lower ? 1 : 0) + (has_digit ? 1 : 0) + (has_special ? 1 : 0);
    return types >= 3;
}

esp_err_t config_manager_init(void)
{
    ESP_LOGI(TAG, "Initializing configuration manager");
    
    // Load configuration from SD card
    esp_err_t ret = config_manager_load();
    if (ret != ESP_OK) {
        ESP_LOGW(TAG, "Failed to load config, using defaults");
        memcpy(&s_current_config, &s_default_config, sizeof(config_t));
        s_first_boot_detected = true;
        
        // Try to save default config
        config_manager_save();
        
        ESP_LOGW(TAG, "FIRST BOOT DETECTED - Please change default passwords!");
        ESP_LOGW(TAG, "WiFi AP Password: %s", s_current_config.wifi_ap.password);
        ESP_LOGW(TAG, "Web Server Password: %s", s_current_config.web_server.password);
    } else {
        // Check if passwords are still default
        if (strcmp(s_current_config.wifi_ap.password, "CHANGE_ME_FIRST_BOOT") == 0 ||
            strcmp(s_current_config.web_server.password, "CHANGE_ME_FIRST_BOOT") == 0) {
            s_first_boot_detected = true;
            ESP_LOGW(TAG, "DEFAULT PASSWORDS DETECTED - Please change them!");
        }
    }
    
    return ESP_OK;
}

esp_err_t config_manager_is_first_boot(bool* is_first_boot)
{
    if (is_first_boot == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    *is_first_boot = s_first_boot_detected;
    return ESP_OK;
}

esp_err_t config_manager_change_password(const char* username, const char* old_password, 
                                       const char* new_password, bool* success)
{
    if (username == NULL || old_password == NULL || new_password == NULL || success == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    
    *success = false;
    
    // Validate current password
    if (strcmp(username, s_current_config.web_server.username) != 0 ||
        !verify_password_hash(old_password, s_current_config.web_server.password)) {
        return ESP_OK; // Authentication failed
    }
    
    // Validate new password strength
    if (!is_password_strong(new_password)) {
        ESP_LOGE(TAG, "New password does not meet strength requirements");
        return ESP_OK; // Password too weak
    }
    
    // Hash the new password
    char salt[33], hash[65];
    esp_err_t ret = security_manager_hash_password(new_password, salt, sizeof(salt), hash, sizeof(hash));
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to hash new password");
        return ret;
    }
    
    // Store salt:hash format
    snprintf(s_current_config.web_server.password, sizeof(s_current_config.web_server.password),
             "%s:%s", salt, hash);
    
    // Save configuration
    ret = config_manager_save();
    if (ret == ESP_OK) {
        *success = true;
        s_first_boot_detected = false;
        ESP_LOGI(TAG, "Password changed successfully");
    }
    
    return ret;
}

esp_err_t config_manager_change_wifi_password(const char* new_password, bool* success)
{
    if (new_password == NULL || success == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    
    *success = false;
    
    // Validate new password strength
    if (!is_password_strong(new_password)) {
        ESP_LOGE(TAG, "New WiFi password does not meet strength requirements");
        return ESP_OK; // Password too weak
    }
    
    // Store new password (WiFi passwords are typically not hashed)
    strncpy(s_current_config.wifi_ap.password, new_password, sizeof(s_current_config.wifi_ap.password) - 1);
    s_current_config.wifi_ap.password[sizeof(s_current_config.wifi_ap.password) - 1] = '\0';
    
    // Save configuration
    esp_err_t ret = config_manager_save();
    if (ret == ESP_OK) {
        *success = true;
        ESP_LOGI(TAG, "WiFi password changed successfully");
    }
    
    return ret;
}

esp_err_t config_manager_load(void)
{
    char *config_data = NULL;
    size_t config_size = 0;
    
    // Read config file from SD card
    char buffer[4096];
    size_t bytes_read = 0;
    esp_err_t ret = sd_manager_read_file("/config/network_config.json", buffer, sizeof(buffer), &bytes_read);
    if (ret == ESP_OK) {
        config_data = malloc(bytes_read + 1);
        if (config_data) {
            memcpy(config_data, buffer, bytes_read);
            config_data[bytes_read] = '\0';
            config_size = bytes_read;
        } else {
            ret = ESP_ERR_NO_MEM;
        }
    }
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "Failed to read config file from SD card");
        return ret;
    }
    
    if (config_data == NULL || config_size == 0) {
        ESP_LOGE(TAG, "Config file is empty");
        free(config_data);
        return ESP_ERR_INVALID_ARG;
    }
    
    // Parse JSON
    cJSON *json = cJSON_Parse(config_data);
    free(config_data);
    
    if (json == NULL) {
        ESP_LOGE(TAG, "Failed to parse JSON config");
        return ESP_ERR_INVALID_ARG;
    }
    
    // Parse WiFi AP config
    cJSON *wifi_ap = cJSON_GetObjectItem(json, "wifi_ap");
    if (wifi_ap) {
        cJSON *ssid = cJSON_GetObjectItem(wifi_ap, "ssid");
        cJSON *password = cJSON_GetObjectItem(wifi_ap, "password");
        cJSON *channel = cJSON_GetObjectItem(wifi_ap, "channel");
        cJSON *max_connections = cJSON_GetObjectItem(wifi_ap, "max_connections");
        cJSON *ip = cJSON_GetObjectItem(wifi_ap, "ip");
        cJSON *gateway = cJSON_GetObjectItem(wifi_ap, "gateway");
        cJSON *netmask = cJSON_GetObjectItem(wifi_ap, "netmask");
        
        if (ssid && cJSON_IsString(ssid)) {
            strncpy(s_current_config.wifi_ap.ssid, ssid->valuestring, sizeof(s_current_config.wifi_ap.ssid) - 1);
        }
        if (password && cJSON_IsString(password)) {
            strncpy(s_current_config.wifi_ap.password, password->valuestring, sizeof(s_current_config.wifi_ap.password) - 1);
        }
        if (channel && cJSON_IsNumber(channel)) {
            s_current_config.wifi_ap.channel = (uint8_t)channel->valueint;
        }
        if (max_connections && cJSON_IsNumber(max_connections)) {
            s_current_config.wifi_ap.max_connections = (uint8_t)max_connections->valueint;
        }
        if (ip && cJSON_IsString(ip)) {
            strncpy(s_current_config.wifi_ap.ip, ip->valuestring, sizeof(s_current_config.wifi_ap.ip) - 1);
        }
        if (gateway && cJSON_IsString(gateway)) {
            strncpy(s_current_config.wifi_ap.gateway, gateway->valuestring, sizeof(s_current_config.wifi_ap.gateway) - 1);
        }
        if (netmask && cJSON_IsString(netmask)) {
            strncpy(s_current_config.wifi_ap.netmask, netmask->valuestring, sizeof(s_current_config.wifi_ap.netmask) - 1);
        }
    }
    
    // Parse Ethernet config
    cJSON *ethernet = cJSON_GetObjectItem(json, "ethernet");
    if (ethernet) {
        cJSON *dhcp_enabled = cJSON_GetObjectItem(ethernet, "dhcp_enabled");
        cJSON *static_ip = cJSON_GetObjectItem(ethernet, "static_ip");
        cJSON *gateway = cJSON_GetObjectItem(ethernet, "gateway");
        cJSON *netmask = cJSON_GetObjectItem(ethernet, "netmask");
        cJSON *dns = cJSON_GetObjectItem(ethernet, "dns");
        
        if (dhcp_enabled && cJSON_IsBool(dhcp_enabled)) {
            s_current_config.ethernet.dhcp_enabled = cJSON_IsTrue(dhcp_enabled);
        }
        if (static_ip && cJSON_IsString(static_ip)) {
            strncpy(s_current_config.ethernet.static_ip, static_ip->valuestring, sizeof(s_current_config.ethernet.static_ip) - 1);
        }
        if (gateway && cJSON_IsString(gateway)) {
            strncpy(s_current_config.ethernet.gateway, gateway->valuestring, sizeof(s_current_config.ethernet.gateway) - 1);
        }
        if (netmask && cJSON_IsString(netmask)) {
            strncpy(s_current_config.ethernet.netmask, netmask->valuestring, sizeof(s_current_config.ethernet.netmask) - 1);
        }
        if (dns && cJSON_IsString(dns)) {
            strncpy(s_current_config.ethernet.dns, dns->valuestring, sizeof(s_current_config.ethernet.dns) - 1);
        }
    }
    
    // Parse Web Server config
    cJSON *web_server = cJSON_GetObjectItem(json, "web_server");
    if (web_server) {
        cJSON *port = cJSON_GetObjectItem(web_server, "port");
        cJSON *auth_enabled = cJSON_GetObjectItem(web_server, "auth_enabled");
        cJSON *username = cJSON_GetObjectItem(web_server, "username");
        cJSON *password = cJSON_GetObjectItem(web_server, "password");
        
        if (port && cJSON_IsNumber(port)) {
            s_current_config.web_server.port = (uint16_t)port->valueint;
        }
        if (auth_enabled && cJSON_IsBool(auth_enabled)) {
            s_current_config.web_server.auth_enabled = cJSON_IsTrue(auth_enabled);
        }
        if (username && cJSON_IsString(username)) {
            strncpy(s_current_config.web_server.username, username->valuestring, sizeof(s_current_config.web_server.username) - 1);
        }
        if (password && cJSON_IsString(password)) {
            strncpy(s_current_config.web_server.password, password->valuestring, sizeof(s_current_config.web_server.password) - 1);
        }
    }
    
    // Parse Scanner config
    cJSON *scanner = cJSON_GetObjectItem(json, "scanner");
    if (scanner) {
        cJSON *arp_timeout = cJSON_GetObjectItem(scanner, "arp_timeout_ms");
        cJSON *ping_timeout = cJSON_GetObjectItem(scanner, "ping_timeout_ms");
        cJSON *port_scan_timeout = cJSON_GetObjectItem(scanner, "port_scan_timeout_ms");
        cJSON *max_ports = cJSON_GetObjectItem(scanner, "max_ports_per_scan");
        cJSON *scan_interval = cJSON_GetObjectItem(scanner, "scan_interval_ms");
        
        if (arp_timeout && cJSON_IsNumber(arp_timeout)) {
            s_current_config.scanner.arp_timeout_ms = (uint32_t)arp_timeout->valueint;
        }
        if (ping_timeout && cJSON_IsNumber(ping_timeout)) {
            s_current_config.scanner.ping_timeout_ms = (uint32_t)ping_timeout->valueint;
        }
        if (port_scan_timeout && cJSON_IsNumber(port_scan_timeout)) {
            s_current_config.scanner.port_scan_timeout_ms = (uint32_t)port_scan_timeout->valueint;
        }
        if (max_ports && cJSON_IsNumber(max_ports)) {
            s_current_config.scanner.max_ports_per_scan = (uint16_t)max_ports->valueint;
        }
        if (scan_interval && cJSON_IsNumber(scan_interval)) {
            s_current_config.scanner.scan_interval_ms = (uint32_t)scan_interval->valueint;
        }
    }
    
    cJSON_Delete(json);
    ESP_LOGI(TAG, "Configuration loaded successfully");
    return ESP_OK;
}

esp_err_t config_manager_save(void)
{
    cJSON *json = cJSON_CreateObject();
    if (json == NULL) {
        ESP_LOGE(TAG, "Failed to create JSON object");
        return ESP_ERR_NO_MEM;
    }
    
    // WiFi AP config
    cJSON *wifi_ap = cJSON_CreateObject();
    cJSON_AddStringToObject(wifi_ap, "ssid", s_current_config.wifi_ap.ssid);
    cJSON_AddStringToObject(wifi_ap, "password", s_current_config.wifi_ap.password);
    cJSON_AddNumberToObject(wifi_ap, "channel", s_current_config.wifi_ap.channel);
    cJSON_AddNumberToObject(wifi_ap, "max_connections", s_current_config.wifi_ap.max_connections);
    cJSON_AddStringToObject(wifi_ap, "ip", s_current_config.wifi_ap.ip);
    cJSON_AddStringToObject(wifi_ap, "gateway", s_current_config.wifi_ap.gateway);
    cJSON_AddStringToObject(wifi_ap, "netmask", s_current_config.wifi_ap.netmask);
    cJSON_AddItemToObject(json, "wifi_ap", wifi_ap);
    
    // Ethernet config
    cJSON *ethernet = cJSON_CreateObject();
    cJSON_AddBoolToObject(ethernet, "dhcp_enabled", s_current_config.ethernet.dhcp_enabled);
    cJSON_AddStringToObject(ethernet, "static_ip", s_current_config.ethernet.static_ip);
    cJSON_AddStringToObject(ethernet, "gateway", s_current_config.ethernet.gateway);
    cJSON_AddStringToObject(ethernet, "netmask", s_current_config.ethernet.netmask);
    cJSON_AddStringToObject(ethernet, "dns", s_current_config.ethernet.dns);
    cJSON_AddItemToObject(json, "ethernet", ethernet);
    
    // Web Server config
    cJSON *web_server = cJSON_CreateObject();
    cJSON_AddNumberToObject(web_server, "port", s_current_config.web_server.port);
    cJSON_AddBoolToObject(web_server, "auth_enabled", s_current_config.web_server.auth_enabled);
    cJSON_AddStringToObject(web_server, "username", s_current_config.web_server.username);
    cJSON_AddStringToObject(web_server, "password", s_current_config.web_server.password);
    cJSON_AddItemToObject(json, "web_server", web_server);
    
    // Scanner config
    cJSON *scanner = cJSON_CreateObject();
    cJSON_AddNumberToObject(scanner, "arp_timeout_ms", s_current_config.scanner.arp_timeout_ms);
    cJSON_AddNumberToObject(scanner, "ping_timeout_ms", s_current_config.scanner.ping_timeout_ms);
    cJSON_AddNumberToObject(scanner, "port_scan_timeout_ms", s_current_config.scanner.port_scan_timeout_ms);
    cJSON_AddNumberToObject(scanner, "max_ports_per_scan", s_current_config.scanner.max_ports_per_scan);
    cJSON_AddNumberToObject(scanner, "scan_interval_ms", s_current_config.scanner.scan_interval_ms);
    cJSON_AddItemToObject(json, "scanner", scanner);
    
    // Convert to string
    char *json_string = cJSON_Print(json);
    cJSON_Delete(json);
    
    if (json_string == NULL) {
        ESP_LOGE(TAG, "Failed to convert JSON to string");
        return ESP_ERR_NO_MEM;
    }
    
    // Write to SD card
    esp_err_t ret = sd_manager_write_file("/config/network_config.json", json_string, strlen(json_string), false);
    free(json_string);
    
    if (ret == ESP_OK) {
        ESP_LOGI(TAG, "Configuration saved successfully");
    } else {
        ESP_LOGE(TAG, "Failed to save configuration");
    }
    
    return ret;
}

const config_t* config_manager_get_config(void)
{
    return &s_current_config;
}

esp_err_t config_manager_update_wifi_ap(const custom_wifi_ap_config_t *config)
{
    if (config == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    
    memcpy(&s_current_config.wifi_ap, config, sizeof(custom_wifi_ap_config_t));
    return config_manager_save();
}

esp_err_t config_manager_update_ethernet(const ethernet_config_t *config)
{
    if (config == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    
    memcpy(&s_current_config.ethernet, config, sizeof(ethernet_config_t));
    return config_manager_save();
}

esp_err_t config_manager_update_web_server(const web_server_config_t *config)
{
    if (config == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    
    memcpy(&s_current_config.web_server, config, sizeof(web_server_config_t));
    return config_manager_save();
}

esp_err_t config_manager_update_scanner(const scanner_config_t *config)
{
    if (config == NULL) {
        return ESP_ERR_INVALID_ARG;
    }
    
    memcpy(&s_current_config.scanner, config, sizeof(scanner_config_t));
    return config_manager_save();
}

esp_err_t config_manager_reset_to_defaults(void)
{
    ESP_LOGI(TAG, "Resetting configuration to defaults");
    memcpy(&s_current_config, &s_default_config, sizeof(config_t));
    return config_manager_save();
} 